diff --git a/.github/workflows/ci-test.yaml b/.github/workflows/ci-test.yaml index b18fc00..c484e99 100644 --- a/.github/workflows/ci-test.yaml +++ b/.github/workflows/ci-test.yaml @@ -27,5 +27,6 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' - run: npm ci + - run: npm check-types - run: npm run build --if-present - run: npm test diff --git a/package-lock.json b/package-lock.json index 69cc50a..c20bd0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2650 +1,8 @@ { "name": "typed-function", "version": "3.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "typed-function", - "version": "3.0.0", - "devDependencies": { - "benchmark": "2.1.4", - "brace-expansion": "2.0.1", - "mocha": "10.0.0", - "nyc": "15.1.0", - "pad-right": "0.2.2", - "uglify-js": "3.15.5" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/benchmark": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", - "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", - "dev": true, - "dependencies": { - "lodash": "^4.17.4", - "platform": "^1.3.3" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.0.tgz", - "integrity": "sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001313", - "electron-to-chromium": "^1.4.76", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001314", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001314.tgz", - "integrity": "sha512-0zaSO+TnCHtHJIbpLroX7nsD+vYuOVjl3uzFbJO1wMVbuveJA0RK2WcQA9ZUIOiO0/ArMiMgHJLxfEZhQiC0kw==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/convert-source-map/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.81", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.81.tgz", - "integrity": "sha512-Gs7xVpIZ7tYYSDA+WgpzwpPvfGwUk3KSIjJ0akuj5XQHFdyQnsUoM76EA4CIHXNLPiVwTwOFay9RMb0ChG3OBw==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/js-yaml/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimatch/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/nyc/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/nyc/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pad-right": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", - "dev": true, - "dependencies": { - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/platform": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz", - "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q==", - "dev": true - }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/spawn-wrap/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/spawn-wrap/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/uglify-js": { - "version": "3.15.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.5.tgz", - "integrity": "sha512-hNM5q5GbBRB5xB+PMqVRcgYe4c8jbyZ1pzZhS6jbq54/4F2gFK869ZheiE5A8/t+W5jtTNpWef/5Q9zk639FNQ==", - "dev": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, "dependencies": { "@ampproject/remapping": { "version": "2.1.2", @@ -4520,6 +1878,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", + "dev": true + }, "uglify-js": { "version": "3.15.5", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.5.tgz", diff --git a/package.json b/package.json index 89aa625..518bec9 100644 --- a/package.json +++ b/package.json @@ -22,16 +22,18 @@ "devDependencies": { "benchmark": "2.1.4", "brace-expansion": "2.0.1", - "nyc": "15.1.0", "mocha": "10.0.0", + "nyc": "15.1.0", "pad-right": "0.2.2", + "typescript": "^4.7.3", "uglify-js": "3.15.5" }, "comment": "brace-expansion is installed because an old insecure version is used by one of the dev depencencies (under istanbul)", "main": "typed-function.js", "scripts": { - "build": "uglifyjs typed-function.js -o typed-function.min.js -c -m", + "build": "tsc typed-function.ts && uglifyjs /typed-function.js", "test": "mocha test --recursive", + "check-types": "tsc --noEmit --incremental false", "coverage": "nyc _mocha -- test --recursive; echo \"\nCoverage report is available at ./coverage/lcov-report/index.html\"", "prepublishOnly": "npm test && npm run build" }, diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d497ac1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + /* Language and Environment */ + "target": "es2016", + + /* Modules */ + "module": "commonjs", + "rootDir": "./", + "moduleResolution": "node", + "baseUrl": "./", + + /* Emit */ + "declaration": true, + "outFile": "./typed-function.js", + + /* Interop Constraints */ + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + + /* Type Checking */ + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "useUnknownInCatchVariables": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "exactOptionalPropertyTypes": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "skipLibCheck": true + } +} diff --git a/typed-function.js b/typed-function.js deleted file mode 100644 index 7684923..0000000 --- a/typed-function.js +++ /dev/null @@ -1,1994 +0,0 @@ -/** - * typed-function - * - * Type checking for JavaScript functions - * - * https://github.com/josdejong/typed-function - */ -'use strict'; - -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define([], factory); - } else if (typeof exports === 'object') { - // OldNode. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like OldNode. - module.exports = factory(); - } else { - // Browser globals (root is window) - root.typed = factory(); - } -}(this, function () { - - function ok () { - return true; - } - - function notOk () { - return false; - } - - function undef () { - return undefined; - } - - const NOT_TYPED_FUNCTION = 'Argument is not a typed-function.' - - /** - * @typedef {{ - * params: Param[], - * fn: function, - * test: function, - * implementation: function - * }} Signature - * - * @typedef {{ - * types: Type[], - * hasAny: boolean, - * hasConversion: boolean, - * restParam: boolean - * }} Param - * - * @typedef {{ - * name: string, - * typeIndex: number, - * test: function, - * isAny: boolean, - * conversion?: ConversionDef, - * conversionIndex: number, - * }} Type - * - * @typedef {{ - * from: string, - * to: string, - * convert: function (*) : * - * }} ConversionDef - * - * @typedef {{ - * name: string, - * test: function(*) : boolean, - * isAny?: boolean - * }} TypeDef - */ - - // create a new instance of typed-function - function create () { - // data type tests - - /** - * Returns true if the argument is a non-null "plain" object - */ - function isPlainObject (x) { - return typeof x === 'object' && x !== null && x.constructor === Object - } - - const _types = [ - { name: 'number', test: function (x) { return typeof x === 'number' } }, - { name: 'string', test: function (x) { return typeof x === 'string' } }, - { name: 'boolean', test: function (x) { return typeof x === 'boolean' } }, - { name: 'Function', test: function (x) { return typeof x === 'function'} }, - { name: 'Array', test: Array.isArray }, - { name: 'Date', test: function (x) { return x instanceof Date } }, - { name: 'RegExp', test: function (x) { return x instanceof RegExp } }, - { name: 'Object', test: isPlainObject }, - { name: 'null', test: function (x) { return x === null } }, - { name: 'undefined', test: function (x) { return x === undefined } } - ]; - - const anyType = { - name: 'any', - test: ok, - isAny: true - } - - // Data structures to track the types. As these are local variables in - // create(), each typed universe will get its own copy, but the variables - // will only be accessible through the (closures of the) functions supplied - // as properties of the typed object, not directly. - // These will be initialized in clear() below - let typeMap; // primary store of all types - let typeList; // Array of just type names, for the sake of ordering - - // And similar data structures for the type conversions: - let nConversions = 0; - // the actual conversions are stored on a property of the destination types - - // This is a temporary object, will be replaced with a function at the end - let typed = { createCount: 0 }; - - /** - * Takes a type name and returns the corresponding official type object - * for that type. - * - * @param {string} typeSpec - * @returns {TypeDef} type - */ - function findType (typeName) { - const type = typeMap.get(typeName) - if (type) { - return type; - } - // Remainder is error handling - let message = 'Unknown type "' + typeName + '"'; - const name = typeName.toLowerCase(); - let otherName; - for (otherName of typeList) { - if (otherName.toLowerCase() === name) { - message += '. Did you mean "' + otherName + '" ?'; - break; - } - } - throw new TypeError(message); - } - - /** - * Adds an array `types` of type definitions to this typed instance. - * Each type definition should be an object with properties: - * 'name' - a string giving the name of the type; 'test' - function - * returning a boolean that tests membership in the type; and optionally - * 'isAny' - true only for the 'any' type. - * - * The second optional argument, `before`, gives the name of a type that - * these types should be added before. The new types are added in the - * order specified. - * @param {TypeDef[]} types - * @param {string} ['any'] before - */ - function addTypes (types, beforeSpec = 'any') { - const beforeIndex = beforeSpec - ? findType(beforeSpec).index - : typeList.length; - const newTypes = []; - for (var i = 0; i < types.length; ++i) { - if (!types[i] || typeof types[i].name !== 'string' || - typeof types[i].test !== 'function') { - throw new TypeError('Object with properties {name: string, test: function} expected'); - } - const typeName = types[i].name; - if (typeMap.has(typeName)) { - throw new TypeError('Duplicate type name "' + typeName + '"'); - } - newTypes.push(typeName); - typeMap.set(typeName, { - name: typeName, - test: types[i].test, - isAny: types[i].isAny, - index: beforeIndex + i, - conversionsTo: [] // Newly added type can't have any conversions to it - }) - } - // update the typeList - const affectedTypes = typeList.slice(beforeIndex); - typeList = - typeList.slice(0,beforeIndex).concat(newTypes).concat(affectedTypes); - // Fix the indices - for (var i = beforeIndex + newTypes.length; i < typeList.length; ++i) { - typeMap.get(typeList[i]).index = i; - } - } - - /** - * Removes all types and conversions from this typed instance. - * May cause previously constructed typed-functions to throw - * strange errors when they are called with types that do not - * match any of their signatures. - */ - function clear () { - typeMap = new Map(); - typeList = []; - nConversions = 0; - addTypes([anyType], false); - } - - // initialize the types to the default list - clear(); - addTypes(_types); - - /** - * Removes all conversions, leaving the types alone. - */ - function clearConversions() { - let typeName; - for (typeName of typeList) { - typeMap.get(typeName).conversionsTo = []; - } - nConversions = 0; - } - - /** - * Find the type names that match a value. - * @param {*} value - * @return {string[]} Array of names of types for which - * the type test matches the value. - */ - function findTypeNames(value) { - const matches = typeList.filter(name => { - const type = typeMap.get(name); - return !type.isAny && type.test(value); - }); - if (matches.length) { - return matches; - } - return ['any']; - } - - /** - * Check if an entity is a typed function created by any instance - * @param {any} entity - * @returns {boolean} - */ - function isTypedFunction(entity) { - return entity && typeof entity === 'function' && - '_typedFunctionData' in entity; - } - - /** - * Find a specific signature from a (composed) typed function, for example: - * - * typed.findSignature(fn, ['number', 'string']) - * typed.findSignature(fn, 'number, string') - * typed.findSignature(fn, 'number,string', {exact: true}) - * - * This function findSignature will by default return the best match to - * the given signature, possibly employing type conversions. - * - * The (optional) third argument is a plain object giving options - * controlling the signature search. Currently the only implemented - * option is `exact`: if specified as true (default is false), only - * exact matches will be returned (i.e. signatures for which `fn` was - * directly defined). Note that a (possibly different) type matching - * `any`, or one or more instances of TYPE matching `...TYPE` are - * considered exact matches in this regard, as no conversions are used. - * - * This function returns a "signature" object, as does `typed.resolve()`, - * which is a plain object with four keys: `params` (the array of parameters - * for this signature), `fn` (the originally supplied function for this - * signature), `test` (a generated function that determines if an argument - * list matches this signature, and `implementation` (the function to call - * on a matching argument list, that performs conversions if necessary and - * then calls the originally supplied function). - * - * @param {Function} fn A typed-function - * @param {string | string[]} signature - * Signature to be found, can be an array or a comma separated string. - * @param {object} options Controls the signature search as documented - * @return {{ params: Param[], fn: function, test: function, implementation: function }} - * Returns the matching signature, or throws an error when no signature - * is found. - */ - function findSignature (fn, signature, exactSpec) { - if (!isTypedFunction(fn)) { - throw new TypeError(NOT_TYPED_FUNCTION); - } - - // Canonicalize input - const exact = exactSpec && exactSpec.exact; - const stringSignature = Array.isArray(signature) - ? signature.join(',') - : signature; - const params = parseSignature(stringSignature); - const canonicalSignature = stringifyParams(params); - - // First hope we get lucky and exactly match a signature - if (!exact || canonicalSignature in fn.signatures) { - // OK, we can check the internal signatures - const match = - fn._typedFunctionData.signatureMap.get(canonicalSignature); - if (match) { - return match; - } - } - - // Oh well, we did not; so we have to go back and check the parameters - // one by one, in order to catch things like `any` and rest params. - // Note here we can assume there is at least one parameter, because - // the empty signature would have matched successfully above. - const nParams = params.length; - let remainingSignatures; - if (exact) { - remainingSignatures = [] - let name; - for (name in fn.signatures) { - remainingSignatures.push(fn._typedFunctionData.signatureMap.get(name)) - } - } else { - remainingSignatures = fn._typedFunctionData.signatures - } - for (var i = 0; i < nParams; ++i) { - const want = params[i]; - const filteredSignatures = []; - let possibility; - for (possibility of remainingSignatures) { - const have = getParamAtIndex(possibility.params, i); - if (!have || (want.restParam && !have.restParam)) { - continue; - } - if (!have.hasAny) { - // have to check all of the wanted types are available - const haveTypes = paramTypeSet(have); - if (want.types.some(wtype => !haveTypes.has(wtype.name))) { - continue; - } - } - // OK, this looks good - filteredSignatures.push(possibility); - } - remainingSignatures = filteredSignatures; - if (remainingSignatures.length === 0) break; - } - // Return the first remaining signature that was totally matched: - let candidate; - for (candidate of remainingSignatures) { - if (candidate.params.length <= nParams) { - return candidate; - } - } - - throw new TypeError('Signature not found (signature: ' + (fn.name || 'unnamed') + '(' + stringifyParams(params, ', ') + '))'); - } - - /** - * Find the proper function to call for a specific signature from - * a (composed) typed function, for example: - * - * typed.find(fn, ['number', 'string']) - * typed.find(fn, 'number, string') - * typed.find(fn, 'number,string', {exact: true}) - * - * This function find will by default return the best match to - * the given signature, possibly employing type conversions (and returning - * a function that will perform those conversions as needed). The - * (optional) third argument is a plain object giving options contolling - * the signature search. Currently only the option `exact` is implemented, - * which defaults to "false". If `exact` is specified as true, then only - * exact matches will be returned (i.e. signatures for which `fn` was - * directly defined). Uses of `any` and `...TYPE` are considered exact if - * no conversions are necessary to apply the corresponding function. - * - * @param {Function} fn A typed-function - * @param {string | string[]} signature - * Signature to be found, can be an array or a comma separated string. - * @param {object} options Controls the signature match as documented - * @return {function} - * Returns the function to call for the given signature, or throws an - * error if no match is found. - */ - function find (fn, signature, exact) { - return findSignature(fn, signature, exact).implementation; - } - - /** - * Convert a given value to another data type, specified by type name. - * - * @param {*} value - * @param {string} type - */ - function convert (value, typeName) { - // check conversion is needed - const type = findType(typeName); - if (type.test(value)) { - return value; - } - const conversions = type.conversionsTo; - if (conversions.length === 0) { - throw new Error( - 'There are no conversions to ' + typeName + ' defined.'); - } - for (var i = 0; i < conversions.length; i++) { - const fromType = findType(conversions[i].from); - if (fromType.test(value)) { - return conversions[i].convert(value); - } - } - - throw new Error('Cannot convert ' + value + ' to ' + typeName); - } - - /** - * Stringify parameters in a normalized way - * @param {Param[]} params - * @param {string} [','] separator - * @return {string} - */ - function stringifyParams (params, separator = ',') { - return params.map(p => p.name).join(separator); - } - - /** - * Parse a parameter, like "...number | boolean" - * @param {string} param - * @return {Param} param - */ - function parseParam (param) { - const restParam = param.indexOf('...') === 0; - const types = (!restParam) - ? param - : (param.length > 3) - ? param.slice(3) - : 'any'; - - const typeDefs = types.split('|').map(s => findType(s.trim())) - - let hasAny = false; - let paramName = restParam ? '...' : ''; - - const exactTypes = typeDefs.map(function (type) { - hasAny = type.isAny || hasAny; - paramName += type.name + '|' - - return { - name: type.name, - typeIndex: type.index, - test: type.test, - isAny: type.isAny, - conversion: null, - conversionIndex: -1 - }; - }); - - return { - types: exactTypes, - name: paramName.slice(0, -1), // remove trailing '|' from above - hasAny: hasAny, - hasConversion: false, - restParam: restParam - }; - } - - /** - * Expands a parsed parameter with the types available from currently - * defined conversions. - * @param {Param} param - * @return {Param} param - */ - function expandParam (param) { - const typeNames = param.types.map(t => t.name); - const matchingConversions = availableConversions(typeNames); - let hasAny = param.hasAny; - let newName = param.name; - - const convertibleTypes = matchingConversions.map(function (conversion) { - const type = findType(conversion.from); - hasAny = type.isAny || hasAny; - newName += '|' + conversion.from; - - return { - name: conversion.from, - typeIndex: type.index, - test: type.test, - isAny: type.isAny, - conversion: conversion, - conversionIndex: conversion.index - }; - }); - - return { - types: param.types.concat(convertibleTypes), - name: newName, - hasAny: hasAny, - hasConversion: convertibleTypes.length > 0, - restParam: param.restParam - }; - } - - /** - * Return the set of type names in a parameter. - * Caches the result for efficiency - * - * @param {Param} param - * @return {Set} typenames - */ - function paramTypeSet (param) { - if (!param.typeSet) { - param.typeSet = new Set(); - param.types.forEach(type => param.typeSet.add(type.name)); - } - return param.typeSet; - } - - /** - * Parse a signature with comma separated parameters, - * like "number | boolean, ...string" - * - * @param {string} signature - * @return {Param[]} params - */ - function parseSignature (rawSignature) { - const params = []; - if (typeof rawSignature !== 'string') { - throw new TypeError('Signatures must be strings'); - } - const signature = rawSignature.trim() - if (signature === '') { - return params; - } - - const rawParams = signature.split(','); - for (var i = 0; i < rawParams.length; ++i) { - const parsedParam = parseParam(rawParams[i].trim()); - if (parsedParam.restParam && (i !== rawParams.length - 1)) { - throw new SyntaxError( - 'Unexpected rest parameter "' + rawParams[i] + '": ' + - 'only allowed for the last parameter'); - } - // if invalid, short-circuit (all of the types may have been filtered) - if (parsedParam.types.length == 0) { - return null; - } - params.push(parsedParam); - } - - return params; - } - - /** - * Test whether a set of params contains a restParam - * @param {Param[]} params - * @return {boolean} Returns true when the last parameter is a restParam - */ - function hasRestParam(params) { - const param = last(params); - return param ? param.restParam : false; - } - - /** - * Create a type test for a single parameter, which can have one or multiple - * types. - * @param {Param} param - * @return {function(x: *) : boolean} Returns a test function - */ - function compileTest(param) { - if (!param || param.types.length === 0) { - // nothing to do - return ok; - } - else if (param.types.length === 1) { - return findType(param.types[0].name).test; - } - else if (param.types.length === 2) { - const test0 = findType(param.types[0].name).test; - const test1 = findType(param.types[1].name).test; - return function or(x) { - return test0(x) || test1(x); - } - } - else { // param.types.length > 2 - const tests = param.types.map(function (type) { - return findType(type.name).test; - }) - return function or(x) { - for (var i = 0; i < tests.length; i++) { - if (tests[i](x)) { - return true; - } - } - return false; - } - } - } - - /** - * Create a test for all parameters of a signature - * @param {Param[]} params - * @return {function(args: Array<*>) : boolean} - */ - function compileTests(params) { - let tests, test0, test1; - - if (hasRestParam(params)) { - // variable arguments like '...number' - tests = initial(params).map(compileTest); - const varIndex = tests.length; - const lastTest = compileTest(last(params)); - const testRestParam = function (args) { - for (var i = varIndex; i < args.length; i++) { - if (!lastTest(args[i])) { - return false; - } - } - return true; - } - - return function testArgs(args) { - for (var i = 0; i < tests.length; i++) { - if (!tests[i](args[i])) { - return false; - } - } - return testRestParam(args) && (args.length >= varIndex + 1); - }; - } - else { - // no variable arguments - if (params.length === 0) { - return function testArgs(args) { - return args.length === 0; - }; - } - else if (params.length === 1) { - test0 = compileTest(params[0]); - return function testArgs(args) { - return test0(args[0]) && args.length === 1; - }; - } - else if (params.length === 2) { - test0 = compileTest(params[0]); - test1 = compileTest(params[1]); - return function testArgs(args) { - return test0(args[0]) && test1(args[1]) && args.length === 2; - }; - } - else { // arguments.length > 2 - tests = params.map(compileTest); - return function testArgs(args) { - for (var i = 0; i < tests.length; i++) { - if (!tests[i](args[i])) { - return false; - } - } - return args.length === tests.length; - }; - } - } - } - - /** - * Find the parameter at a specific index of a Params list. - * Handles rest parameters. - * @param {Param[]} params - * @param {number} index - * @return {Param | null} Returns the matching parameter when found, - * null otherwise. - */ - function getParamAtIndex(params, index) { - return index < params.length - ? params[index] - : hasRestParam(params) ? last(params) : null - } - - /** - * Get all type names of a parameter - * @param {Params[]} params - * @param {number} index - * @return {string[]} Returns an array with type names - */ - function getTypeSetAtIndex (params, index) { - const param = getParamAtIndex(params, index); - if (!param) { - return new Set(); - } - return paramTypeSet(param); - } - - /** - * Returns the name of a type - * @param {Type} type - * @return {string} Returns the type name - */ - function getTypeName(type) { - return type.name; - } - - /** - * Test whether a type is an exact type or conversion - * @param {Type} type - * @return {boolean} Returns true when - */ - function isExactType(type) { - return type.conversion === null || type.conversion === undefined; - } - - /** - * Helper function for creating error messages: create an array with - * all available types on a specific argument index. - * @param {Signature[]} signatures - * @param {number} index - * @return {string[]} Returns an array with available types - */ - function mergeExpectedParams(signatures, index) { - const typeSet = new Set(); - signatures.forEach(signature => { - const paramSet = getTypeSetAtIndex(signature.params, index); - let name; - for (name of paramSet) { - typeSet.add(name); - } - }); - - return typeSet.has('any') ? ['any'] : Array.from(typeSet); - } - - /** - * Create - * @param {string} name The name of the function - * @param {array.<*>} args The actual arguments passed to the function - * @param {Signature[]} signatures A list with available signatures - * @return {TypeError} Returns a type error with additional data - * attached to it in the property `data` - */ - function createError(name, args, signatures) { - let err, expected; - const _name = name || 'unnamed'; - - // test for wrong type at some index - let matchingSignatures = signatures; - for (var index = 0; index < args.length; index++) { - const nextMatchingDefs = []; - matchingSignatures.forEach(signature => { - const param = getParamAtIndex(signature.params, index); - const test = compileTest(param); - if ((index < signature.params.length - || hasRestParam(signature.params)) && - test(args[index])) { - nextMatchingDefs.push(signature); - } - }); - - if (nextMatchingDefs.length === 0) { - // no matching signatures anymore, throw error "wrong type" - expected = mergeExpectedParams(matchingSignatures, index); - if (expected.length > 0) { - const actualTypes = findTypeNames(args[index]); - - err = new TypeError('Unexpected type of argument in function ' + _name + - ' (expected: ' + expected.join(' or ') + - ', actual: ' + actualTypes.join(' | ') + ', index: ' + index + ')'); - err.data = { - category: 'wrongType', - fn: _name, - index: index, - actual: actualTypes, - expected: expected - } - return err; - } - } - else { - matchingSignatures = nextMatchingDefs; - } - } - - // test for too few arguments - const lengths = matchingSignatures.map(function (signature) { - return hasRestParam(signature.params) - ? Infinity - : signature.params.length; - }); - if (args.length < Math.min.apply(null, lengths)) { - expected = mergeExpectedParams(matchingSignatures, index); - err = new TypeError('Too few arguments in function ' + _name + - ' (expected: ' + expected.join(' or ') + - ', index: ' + args.length + ')'); - err.data = { - category: 'tooFewArgs', - fn: _name, - index: args.length, - expected: expected - } - return err; - } - - // test for too many arguments - const maxLength = Math.max.apply(null, lengths); - if (args.length > maxLength) { - err = new TypeError('Too many arguments in function ' + _name + - ' (expected: ' + maxLength + ', actual: ' + args.length + ')'); - err.data = { - category: 'tooManyArgs', - fn: _name, - index: args.length, - expectedLength: maxLength - } - return err; - } - - // Generic error - const argTypes = []; - for (var i = 0; i < args.length; ++i) { - argTypes.push(findTypeNames(args[i]).join('|')) - } - err = new TypeError('Arguments of type "' + argTypes.join(', ') + - '" do not match any of the defined signatures of function ' + _name + '.'); - err.data = { - category: 'mismatch', - actual: argTypes - } - return err; - } - - /** - * Find the lowest index of all exact types of a parameter (no conversions) - * @param {Param} param - * @return {number} Returns the index of the lowest type in typed.types - */ - function getLowestTypeIndex (param) { - let min = typeList.length + 1; - - for (var i = 0; i < param.types.length; i++) { - if (isExactType(param.types[i])) { - min = Math.min(min, param.types[i].typeIndex); - } - } - - return min; - } - - /** - * Find the lowest index of the conversion of all types of the parameter - * having a conversion - * @param {Param} param - * @return {number} Returns the lowest index of the conversions of this type - */ - function getLowestConversionIndex (param) { - let min = nConversions + 1; - - for (var i = 0; i < param.types.length; i++) { - if (!isExactType(param.types[i])) { - min = Math.min(min, param.types[i].conversionIndex); - } - } - - return min; - } - - /** - * Compare two params - * @param {Param} param1 - * @param {Param} param2 - * @return {number} returns -1 when param1 must get a lower - * index than param2, 1 when the opposite, - * or zero when both are equal - */ - function compareParams (param1, param2) { - // We compare a number of metrics on a param in turn: - // 1) 'any' parameters are the least preferred - if (param1.hasAny) { - if (!param2.hasAny) { - return 1; - } - } - else if (param2.hasAny) { - return -1; - } - - // 2) Prefer non-rest to rest parameters - if (param1.restParam) { - if (!param2.restParam) { - return 1; - } - } else if (param2.restParam) { - return -1; - } - - // 3) Prefer exact type match to conversions - if (param1.hasConversion) { - if (!param2.hasConversion) { - return 1; - } - } else if (param2.hasConversion) { - return -1; - } - - // 4) Prefer lower type index: - const typeDiff = getLowestTypeIndex(param1) - getLowestTypeIndex(param2) - if (typeDiff < 0) { - return -1; - } - if (typeDiff > 0) { - return 1; - } - - // 5) Prefer lower conversion index - const convDiff = - getLowestConversionIndex(param1) - getLowestConversionIndex(param2) - if (convDiff < 0) { - return -1; - } - if (convDiff > 0) { - return 1; - } - - // Don't have a basis for preference - return 0; - } - - /** - * Compare two signatures - * @param {Signature} signature1 - * @param {Signature} signature2 - * @return {number} returns a negative number when param1 must get a lower - * index than param2, a positive number when the opposite, - * or zero when both are equal - */ - function compareSignatures (signature1, signature2) { - const pars1 = signature1.params - const pars2 = signature2.params - const last1 = last(pars1) - const last2 = last(pars2) - const hasRest1 = hasRestParam(pars1) - const hasRest2 = hasRestParam(pars2) - // We compare a number of metrics on signatures in turn: - // 1) An "any rest param" is least preferred - if (hasRest1 && last1.hasAny) { - if (!hasRest2 || !last2.hasAny) { - return 1; - } - } else if (hasRest2 && last2.hasAny) { - return -1; - } - - // 2) Minimize the number of 'any' parameters - let any1 = 0; - let conv1 = 0; - let par; - for (par of pars1) { - if (par.hasAny) ++any1; - if (par.hasConversion) ++conv1; - } - let any2 = 0; - let conv2 = 0; - for (par of pars2) { - if (par.hasAny) ++any2; - if (par.hasConversion) ++conv2; - } - if (any1 !== any2) { - return any1 - any2; - } - - // 3) A conversion rest param is less preferred - if (hasRest1 && last1.hasConversion) { - if (!hasRest2 || !last2.hasConversion) { - return 1; - } - } else if (hasRest2 && last2.hasConversion) { - return -1; - } - - // 4) Minimize the number of conversions - if (conv1 !== conv2) { - return conv1 - conv2; - } - - // 5) Prefer no rest param - if (hasRest1) { - if (!hasRest2) { - return 1; - } - } else if (hasRest2) { - return -1; - } - - // 6) Prefer shorter with rest param, longer without - const lengthCriterion = - (pars1.length - pars2.length) * (hasRest1 ? -1 : 1) - if (lengthCriterion !== 0) { - return lengthCriterion; - } - - // Signatures are identical in each of the above metrics. - // In particular, they are the same length. - // We can therefore compare the parameters one by one. - // First we count which signature has more preferred parameters. - const comparisons = []; - let tc = 0; - for (let i = 0; i < pars1.length; ++i) { - const thisComparison = compareParams(pars1[i], pars2[i]) - comparisons.push(thisComparison) - tc += thisComparison - } - if (tc !== 0) { - return tc; - } - - // They have the same number of preferred parameters, so go by the - // earliest parameter in which we have a preference. - // In other words, dispatch is driven somewhat more by earlier - // parameters than later ones. - let c; - for (c of comparisons) { - if (c !== 0) { - return c; - } - } - - // It's a tossup: - return 0; - } - - /** - * Produce a list of all conversions from distinct types to one of - * the given types. - * - * @param {string[]} typeNames - * @return {ConversionDef[]} Returns the conversions that are available - * resulting in any given type (if any) - */ - function availableConversions(typeNames) { - if (typeNames.length === 0) { - return []; - } - const types = typeNames.map(findType); - if (typeNames.length > 1) { - types.sort((t1, t2) => t1.index - t2.index); - } - let matches = types[0].conversionsTo; - if (typeNames.length === 1) { - return matches; - } - - matches = matches.concat([]) // shallow copy the matches - // Since the types are now in index order, we just want the first - // occurrence of any from type: - const knownTypes = new Set(typeNames); - for (var i = 1; i < types.length; ++i) { - let newMatch; - for (newMatch of types[i].conversionsTo) { - if (!knownTypes.has(newMatch.from)) { - matches.push(newMatch); - knownTypes.add(newMatch.from); - } - } - } - - return matches; - } - - /** - * Preprocess arguments before calling the original function: - * - if needed convert the parameters - * - in case of rest parameters, move the rest parameters into an Array - * @param {Param[]} params - * @param {function} fn - * @return {function} Returns a wrapped function - */ - function compileArgsPreprocessing(params, fn) { - let fnConvert = fn; - - // TODO: can we make this wrapper function smarter/simpler? - - if (params.some(p => p.hasConversion)) { - const restParam = hasRestParam(params); - const compiledConversions = params.map(compileArgConversion); - - fnConvert = function convertArgs() { - const args = []; - const last = restParam ? arguments.length - 1 : arguments.length; - for (var i = 0; i < last; i++) { - args[i] = compiledConversions[i](arguments[i]); - } - if (restParam) { - args[last] = arguments[last].map(compiledConversions[last]); - } - - return fn.apply(this, args); - } - } - - let fnPreprocess = fnConvert; - if (hasRestParam(params)) { - const offset = params.length - 1; - - fnPreprocess = function preprocessRestParams () { - return fnConvert.apply(this, - slice(arguments, 0, offset).concat([slice(arguments, offset)])); - } - } - - return fnPreprocess; - } - - /** - * Compile conversion for a parameter to the right type - * @param {Param} param - * @return {function} Returns the wrapped function that will convert arguments - * - */ - function compileArgConversion(param) { - let test0, test1, conversion0, conversion1; - const tests = []; - const conversions = []; - - param.types.forEach(function (type) { - if (type.conversion) { - tests.push(findType(type.conversion.from).test); - conversions.push(type.conversion.convert); - } - }); - - // create optimized conversion functions depending on the number of conversions - switch (conversions.length) { - case 0: - return function convertArg(arg) { - return arg; - } - - case 1: - test0 = tests[0] - conversion0 = conversions[0]; - return function convertArg(arg) { - if (test0(arg)) { - return conversion0(arg) - } - return arg; - } - - case 2: - test0 = tests[0] - test1 = tests[1] - conversion0 = conversions[0]; - conversion1 = conversions[1]; - return function convertArg(arg) { - if (test0(arg)) { - return conversion0(arg) - } - if (test1(arg)) { - return conversion1(arg) - } - return arg; - } - - default: - return function convertArg(arg) { - for (var i = 0; i < conversions.length; i++) { - if (tests[i](arg)) { - return conversions[i](arg); - } - } - return arg; - } - } - } - - /** - * Split params with union types in to separate params. - * - * For example: - * - * splitParams([['Array', 'Object'], ['string', 'RegExp']) - * // returns: - * // [ - * // ['Array', 'string'], - * // ['Array', 'RegExp'], - * // ['Object', 'string'], - * // ['Object', 'RegExp'] - * // ] - * - * @param {Param[]} params - * @return {Param[]} - */ - function splitParams(params) { - function _splitParams(params, index, paramsSoFar) { - if (index < params.length) { - const param = params[index]; - let resultingParams = []; - - if (param.restParam) { - // split the types of a rest parameter in two: - // one with only exact types, and one with exact types and conversions - const exactTypes = param.types.filter(isExactType); - if (exactTypes.length < param.types.length) { - resultingParams.push({ - types: exactTypes, - name: '...' + exactTypes.map(t => t.name).join('|'), - hasAny: exactTypes.some(t => t.isAny), - hasConversion: false, - restParam: true - }) - } - resultingParams.push(param); - } - else { - // split all the types of a regular parameter into one type per param - resultingParams = param.types.map(function (type) { - return { - types: [type], - name: type.name, - hasAny: type.isAny, - hasConversion: type.conversion, - restParam: false - } - }) - } - - // recurse over the groups with types - return flatMap(resultingParams, function (nextParam) { - return _splitParams(params, index + 1, paramsSoFar.concat([nextParam])); - }); - - } - else { - // we've reached the end of the parameters. - return [paramsSoFar]; - } - } - - return _splitParams(params, 0, []); - } - - /** - * Test whether two param lists represent conflicting signatures - * @param {Param[]} params1 - * @param {Param[]} params2 - * @return {boolean} Returns true when the signatures conflict, false otherwise. - */ - function conflicting(params1, params2) { - const ii = Math.max(params1.length, params2.length); - - for (var i = 0; i < ii; i++) { - const typeSet1 = getTypeSetAtIndex(params1, i); - const typeSet2 = getTypeSetAtIndex(params2, i); - let overlap = false; - let name; - for (name of typeSet2) { - if (typeSet1.has(name)) { - overlap = true; - break; - } - } - if (!overlap) { - return false; - } - } - - const len1 = params1.length; - const len2 = params2.length; - const restParam1 = hasRestParam(params1); - const restParam2 = hasRestParam(params2); - - return restParam1 - ? restParam2 ? (len1 === len2) : (len2 >= len1) - : restParam2 ? (len1 >= len2) : (len1 === len2) - } - - /** - * Helper function for `resolveReferences` that returns a copy of - * functionList wihe any prior resolutions cleared out, in case we are - * recycling signatures from a prior typed function construction. - * - * @param {Array.} functionList - * @return {Array.} - */ - function clearResolutions(functionList) { - return functionList.map(fn => { - if (isReferToSelf(fn)) { - return referToSelf(fn.referToSelf.callback); - } - if (isReferTo(fn)) { - return makeReferTo(fn.referTo.references, fn.referTo.callback); - } - return fn; - }); - } - - /** - * Take a list of references, a list of functions functionList, and a - * signatureMap indexing signatures into functionList, and return - * the list of resolutions, or a false-y value if they don't all - * resolve in a valid way (yet). - * - * @param {string[]} references - * @param {Array} signatureMap - * @return {function[] | false} resolutions - */ - function collectResolutions(references, functionList, signatureMap) { - const resolvedReferences = [] - let reference; - for (reference of references) { - let resolution = signatureMap[reference]; - if (typeof resolution !== 'number') { - throw new TypeError( - 'No definition for referenced signature "' + reference + '"'); - } - resolution = functionList[resolution]; - if (typeof resolution !== 'function') { - return false; - } - resolvedReferences.push(resolution); - } - return resolvedReferences; - } - - /** - * Resolve any references in the functionList for the typed function - * itself. The signatureMap tells which index in the functionList a - * given signature should be mapped to (for use in resolving typed.referTo) - * and self provides the destions of a typed.referToSelf. - * - * @param {Array} functionList - * @param {Object.} signatureMap - * @param {function} self The typed-function itself - * @return {Array} The list of resolved functions - */ - function resolveReferences(functionList, signatureMap, self) { - let resolvedFunctions = clearResolutions(functionList); - let leftUnresolved = true; - while (leftUnresolved) { - leftUnresolved = false; - let nothingResolved = true; - for (var i = 0; i < resolvedFunctions.length; ++i) { - const fn = resolvedFunctions[i] - - if (isReferToSelf(fn)) { - resolvedFunctions[i] = fn.referToSelf.callback(self); - // Preserve reference in case signature is reused someday: - resolvedFunctions[i].referToSelf = fn.referToSelf; - nothingResolved = false - } else if (isReferTo(fn)) { - const resolvedReferences = collectResolutions( - fn.referTo.references, resolvedFunctions, signatureMap); - if (resolvedReferences) { - resolvedFunctions[i] = - fn.referTo.callback.apply(this, resolvedReferences); - // Preserve reference in case signature is reused someday: - resolvedFunctions[i].referTo = fn.referTo; - nothingResolved = false; - } else { - leftUnresolved = true; - } - } - } - - if (nothingResolved && leftUnresolved) { - throw new SyntaxError( - 'Circular reference detected in resolving typed.referTo'); - } - } - - return resolvedFunctions; - } - - /** - * Validate whether any of the function bodies contains a self-reference - * usage like `this(...)` or `this.signatures`. This self-referencing is - * deprecated since typed-function v3. It has been replaced with - * the functions typed.referTo and typed.referToSelf. - * @param {Object.} signaturesMap - */ - function validateDeprecatedThis(signaturesMap) { - // TODO: remove this deprecation warning logic some day (it's introduced in v3) - - // match occurrences like 'this(' and 'this.signatures' - var deprecatedThisRegex = /\bthis(\(|\.signatures\b)/; - - Object.keys(signaturesMap).forEach(signature => { - var fn = signaturesMap[signature]; - - if (deprecatedThisRegex.test(fn.toString())) { - throw new SyntaxError('Using `this` to self-reference a function ' + - 'is deprecated since typed-function@3. ' + - 'Use typed.referTo and typed.referToSelf instead.'); - } - }); - } - - /** - * Create a typed function - * @param {String} name The name for the typed function - * @param {Object.} signaturesMap - * An object with one or - * multiple signatures as key, and the - * function corresponding to the - * signature as value. - * @return {function} Returns the created typed function. - */ - function createTypedFunction(name, rawSignaturesMap) { - typed.createCount++ - - if (Object.keys(rawSignaturesMap).length === 0) { - throw new SyntaxError('No signatures provided'); - } - - if (typed.warnAgainstDeprecatedThis) { - validateDeprecatedThis(rawSignaturesMap); - } - - // Main processing loop for signatures - const parsedParams = []; - const originalFunctions = []; - const signaturesMap = {}; - const preliminarySignatures = [] // may have duplicates from conversions - let signature; - for (signature in rawSignaturesMap) { - // A) Protect against polluted Object prototype: - if (!Object.prototype.hasOwnProperty.call(rawSignaturesMap, signature)) { - continue; - } - // B) Parse the signature - const params = parseSignature(signature); - if (!params) continue; - // C) Check for conflicts - parsedParams.forEach(function (pp) { - if (conflicting(pp, params)) { - throw new TypeError('Conflicting signatures "' + - stringifyParams(pp) + '" and "' + - stringifyParams(params) + '".'); - } - }) - parsedParams.push(params) - // D) Store the provided function and add conversions - const functionIndex = originalFunctions.length; - originalFunctions.push(rawSignaturesMap[signature]) - const conversionParams = params.map(expandParam) - // E) Split the signatures and collect them up - let sp; - for (sp of splitParams(conversionParams)) { - const spName = stringifyParams(sp); - preliminarySignatures.push( - {params: sp, name: spName, fn: functionIndex}); - if (sp.every(p => !p.hasConversion)) { - signaturesMap[spName] = functionIndex; - } - } - } - - preliminarySignatures.sort(compareSignatures); - - // Note the forward reference to the_typed_fn - const resolvedFunctions = - resolveReferences(originalFunctions, signaturesMap, the_typed_fn); - - // Fill in the proper function for each signature - let s; - for (s in signaturesMap) { - if (Object.prototype.hasOwnProperty.call(signaturesMap, s)) { - signaturesMap[s] = resolvedFunctions[signaturesMap[s]] - } - } - const signatures = [] - const internalSignatureMap = new Map() // benchmarks faster than object - for (s of preliminarySignatures) { - // Note it's only safe to eliminate duplicates like this - // _after_ the signature sorting step above; otherwise we might - // remove the wrong one. - if (!internalSignatureMap.has(s.name)) { - s.fn = resolvedFunctions[s.fn] - signatures.push(s) - internalSignatureMap.set(s.name, s) - } - } - - // we create a highly optimized checks for the first couple of signatures with max 2 arguments - const ok0 = signatures[0] && signatures[0].params.length <= 2 && !hasRestParam(signatures[0].params); - const ok1 = signatures[1] && signatures[1].params.length <= 2 && !hasRestParam(signatures[1].params); - const ok2 = signatures[2] && signatures[2].params.length <= 2 && !hasRestParam(signatures[2].params); - const ok3 = signatures[3] && signatures[3].params.length <= 2 && !hasRestParam(signatures[3].params); - const ok4 = signatures[4] && signatures[4].params.length <= 2 && !hasRestParam(signatures[4].params); - const ok5 = signatures[5] && signatures[5].params.length <= 2 && !hasRestParam(signatures[5].params); - const allOk = ok0 && ok1 && ok2 && ok3 && ok4 && ok5; - - // compile the tests - for (var i = 0; i < signatures.length; ++i) { - signatures[i].test = compileTests(signatures[i].params); - } - - const test00 = ok0 ? compileTest(signatures[0].params[0]) : notOk; - const test10 = ok1 ? compileTest(signatures[1].params[0]) : notOk; - const test20 = ok2 ? compileTest(signatures[2].params[0]) : notOk; - const test30 = ok3 ? compileTest(signatures[3].params[0]) : notOk; - const test40 = ok4 ? compileTest(signatures[4].params[0]) : notOk; - const test50 = ok5 ? compileTest(signatures[5].params[0]) : notOk; - - const test01 = ok0 ? compileTest(signatures[0].params[1]) : notOk; - const test11 = ok1 ? compileTest(signatures[1].params[1]) : notOk; - const test21 = ok2 ? compileTest(signatures[2].params[1]) : notOk; - const test31 = ok3 ? compileTest(signatures[3].params[1]) : notOk; - const test41 = ok4 ? compileTest(signatures[4].params[1]) : notOk; - const test51 = ok5 ? compileTest(signatures[5].params[1]) : notOk; - - // compile the functions - for (var i = 0; i < signatures.length; ++i) { - signatures[i].implementation = - compileArgsPreprocessing(signatures[i].params, signatures[i].fn); - } - - const fn0 = ok0 ? signatures[0].implementation : undef; - const fn1 = ok1 ? signatures[1].implementation : undef; - const fn2 = ok2 ? signatures[2].implementation : undef; - const fn3 = ok3 ? signatures[3].implementation : undef; - const fn4 = ok4 ? signatures[4].implementation : undef; - const fn5 = ok5 ? signatures[5].implementation : undef; - - const len0 = ok0 ? signatures[0].params.length : -1; - const len1 = ok1 ? signatures[1].params.length : -1; - const len2 = ok2 ? signatures[2].params.length : -1; - const len3 = ok3 ? signatures[3].params.length : -1; - const len4 = ok4 ? signatures[4].params.length : -1; - const len5 = ok5 ? signatures[5].params.length : -1; - - // simple and generic, but also slow - const iStart = allOk ? 6 : 0; - const iEnd = signatures.length; - // de-reference ahead for execution speed: - const tests = signatures.map(s => s.test) - const fns = signatures.map(s => s.implementation) - const generic = function generic() { - 'use strict'; - - for (var i = iStart; i < iEnd; i++) { - if (tests[i](arguments)) { - return fns[i].apply(this, arguments); - } - } - - return typed.onMismatch(name, arguments, signatures); - } - - // create the typed function - // fast, specialized version. Falls back to the slower, generic one if needed - function the_typed_fn (arg0, arg1) { - 'use strict'; - - if (arguments.length === len0 && test00(arg0) && test01(arg1)) { return fn0.apply(this, arguments); } - if (arguments.length === len1 && test10(arg0) && test11(arg1)) { return fn1.apply(this, arguments); } - if (arguments.length === len2 && test20(arg0) && test21(arg1)) { return fn2.apply(this, arguments); } - if (arguments.length === len3 && test30(arg0) && test31(arg1)) { return fn3.apply(this, arguments); } - if (arguments.length === len4 && test40(arg0) && test41(arg1)) { return fn4.apply(this, arguments); } - if (arguments.length === len5 && test50(arg0) && test51(arg1)) { return fn5.apply(this, arguments); } - - return generic.apply(this, arguments); - } - - // attach name the typed function - try { - Object.defineProperty(the_typed_fn, 'name', {value: name}); - } - catch (err) { - // old browsers do not support Object.defineProperty and some don't support setting the name property - // the function name is not essential for the functioning, it's mostly useful for debugging, - // so it's fine to have unnamed functions. - } - - // attach signatures to the function. - // This property is close to the original collection of signatures - // used to create the typed-function, just with unions split: - the_typed_fn.signatures = signaturesMap; - - // Store internal data for functions like resolve, find, etc. - // Also serves as the flag that this is a typed-function - the_typed_fn._typedFunctionData = { - signatures: signatures, - signatureMap: internalSignatureMap - }; - - return the_typed_fn; - } - - /** - * Action to take on mismatch - * @param {string} name Name of function that was attempted to be called - * @param {Array} args Actual arguments to the call - * @param {Array} signatures Known signatures of the named typed-function - */ - function _onMismatch(name, args, signatures) { - throw createError(name, args, signatures); - } - - /** - * Return all but the last items of an array or function Arguments - * @param {Array | Arguments} arr - * @return {Array} - */ - function initial(arr) { - return slice(arr, 0, arr.length - 1); - } - - /** - * return the last item of an array or function Arguments - * @param {Array | Arguments} arr - * @return {*} - */ - function last(arr) { - return arr[arr.length - 1]; - } - - /** - * Slice an array or function Arguments - * @param {Array | Arguments | IArguments} arr - * @param {number} start - * @param {number} [end] - * @return {Array} - */ - function slice(arr, start, end) { - return Array.prototype.slice.call(arr, start, end); - } - - /** - * Return the first item from an array for which test(arr[i]) returns true - * @param {Array} arr - * @param {function} test - * @return {* | undefined} Returns the first matching item - * or undefined when there is no match - */ - function findInArray(arr, test) { - for (var i = 0; i < arr.length; i++) { - if (test(arr[i])) { - return arr[i]; - } - } - return undefined; - } - - /** - * Flat map the result invoking a callback for every item in an array. - * https://gist.github.com/samgiles/762ee337dff48623e729 - * @param {Array} arr - * @param {function} callback - * @return {Array} - */ - function flatMap(arr, callback) { - return Array.prototype.concat.apply([], arr.map(callback)); - } - - /** - * Create a reference callback to one or multiple signatures - * - * Syntax: - * - * typed.referTo(signature1, signature2, ..., function callback(fn1, fn2, ...) { - * // ... - * }) - * - * @returns {{referTo: {references: string[], callback}}} - */ - function referTo() { - let references = - initial(arguments).map(s => stringifyParams(parseSignature(s))); - const callback = last(arguments); - - if (typeof callback !== 'function') { - throw new TypeError('Callback function expected as last argument'); - } - - return makeReferTo(references, callback) - } - - function makeReferTo(references, callback) { - return { referTo: { references: references, callback: callback } } - } - - /** - * Create a reference callback to the typed-function itself - * - * @param {(self: function) => function} callback - * @returns {{referToSelf: { callback: function }}} - */ - function referToSelf(callback) { - if (typeof callback !== 'function') { - throw new TypeError('Callback function expected as first argument'); - } - - return { referToSelf: { callback: callback } }; - } - - /** - * Test whether something is a referTo object, holding a list with reference - * signatures and a callback. - * - * @param {Object | function} objectOrFn - * @returns {boolean} - */ - function isReferTo(objectOrFn) { - return objectOrFn && - typeof objectOrFn.referTo === 'object' && - Array.isArray(objectOrFn.referTo.references) && - typeof objectOrFn.referTo.callback === 'function'; - } - - /** - * Test whether something is a referToSelf object, holding a callback where - * to pass `self`. - * - * @param {Object | function} objectOrFn - * @returns {boolean} - */ - function isReferToSelf(objectOrFn) { - return objectOrFn && - typeof objectOrFn.referToSelf === 'object' && - typeof objectOrFn.referToSelf.callback === 'function'; - } - - /** - * Check if name is (A) new, (B) a match, or (C) a mismatch; and throw - * an error in case (C). - * - * @param { string | undefined } nameSoFar - * @param { string | undefined } newName - * @returns { string } updated name - */ - function checkName (nameSoFar, newName) { - if (!nameSoFar) { - return newName; - } - if (newName && newName != nameSoFar) { - const err = new Error('Function names do not match (expected: ' + - nameSoFar + ', actual: ' + newName + ')'); - err.data = { actual: newName, expected: nameSoFar }; - throw err; - } - return nameSoFar; - } - - /** - * Retrieve the implied name from an object with signature keys - * and function values, checking whether all value names match - * - * @param { {string: function} } obj - */ - function getObjectName (obj) { - let name - for (let key in obj) { - // Only pay attention to own properties, and only if their values - // are typed functions or functions with a signature property - if (obj.hasOwnProperty(key) && - (isTypedFunction(obj[key]) || - typeof obj[key].signature === 'string')) { - name = checkName(name, obj[key].name) - } - } - return name - } - - /** - * Copy all of the signatures from the second argument into the first, - * which is modified by side effect, checking for conflicts - * - * @param {Object. (c.from === conversion.from)) - if (!existingConversion) { - throw new Error( - 'Attempt to remove nonexistent conversion from ' + conversion.from + - ' to ' + conversion.to); - } - if (existingConversion.convert !== conversion.convert) { - throw new Error( - 'Conversion to remove does not match existing conversion'); - } - const index = to.conversionsTo.indexOf(existingConversion); - to.conversionsTo.splice(index, 1); - } - - /** - * Produce the specific signature that a typed function - * will execute on the given arguments. Here, a "signature" is an - * object with properties 'params', 'test', 'fn', and 'implementation'. - * This last property is a function that converts params as necessary - * and then calls 'fn'. Returns null if there is no matching signature. - * @param {typed-function} tf - * @param {any[]} argList - * @returns {{params: string, test: function, fn: function, implementation: function}} - */ - typed.resolve = function (tf, argList) { - if (!isTypedFunction(tf)) { - throw new TypeError(NOT_TYPED_FUNCTION); - } - const sigs = tf._typedFunctionData.signatures; - for (var i = 0; i < sigs.length; ++i) { - if (sigs[i].test(argList)) { - return sigs[i]; - } - } - return null; - } - - return typed; - } - - return create(); -})); diff --git a/typed-function.ts b/typed-function.ts new file mode 100644 index 0000000..4e14e62 --- /dev/null +++ b/typed-function.ts @@ -0,0 +1,2254 @@ +/** + * typed-function + * + * Type checking for JavaScript functions + * + * https://github.com/josdejong/typed-function + */ + +function ok() { + return true +} + +function notOk() { + return false +} + +function undef() { + return undefined +} + +const NOT_TYPED_FUNCTION = "Argument is not a typed-function." + +export type Signature = { + name: string + params: Param[] + fn: () => void // TODO fix + test: (x: any) => boolean + implementation: (...args: any[]) => any // TODO figure out what this should be +} + +export type PrelimianarySignature = { + fn: number +} + +export type Param = { + types: Type[] + hasAny: boolean + hasConversion: boolean + restParam: boolean + name: string + typeSet: Set +} + +export type Type = { + name: string + typeIndex: number + test: TestFunction + isAny: boolean + conversion: ConversionDef | null + conversionIndex: number +} + +export type ConversionDef = { + from: string + to: string + convert: ConversionDefConvertFunction + index: number +} + +export type ConversionDefConvertFunction = (x: any) => void + +export type TypeDef = { + name: string + test: TestFunction + isAny: boolean + index: number // TODO check if should be non null? + conversionsTo: ConversionDef[] // TODO +} + +export type OnMismatchFn = (name: string, args: TArg[], signatures: Signature[]) => never +export type CreateErrorFn = (name: string, args: TArg[], signatures: Signature[]) => TypedFunctionTypeError +export type ClearFn = () => void +export type ClearConversionsFn = () => void + +export type AddTypesFn = (types: TypeDef[], beforeSpec: "any" | "Object" | false) => void + +export type FindTypeFn = (typeName: string) => TypeDef +export type ReferToFn = (...args: Signature[]) => TypedReferenceTo +export type ReferToSelfFn = (callback: (self: Function) => Function) => TypedReference +export type ConvertFn = (value: any, typeName: string) => false + +export type FindSignatureOptions = { exact: boolean } +export type FindSignatureFn = (fn: TypedFunction, signature: string | string[], options?: FindSignatureOptions) => Signature +export type FindFn = (fn: TypedFunction, signature: string | string[], options?: FindSignatureOptions) => Signature['implementation'] + +export type IsTypedFunctionFn = (entity: any) => entity is TypedFunction +export type AddTypeFn = (type: TypeDef, beforeObjectTest: boolean) => void +export type AddConversionFn = (conversion: ConversionDef) => void +export type AddConversionsFn = (conversion: ConversionDef[]) => void +export type RemoveConversionFn = (conversion: ConversionDef) => void +export type ResolveFn = (tf: TypedFunction, argList: any[]) => Signature | null + +export interface TypedFunction { + (...args: any[]): any // TODO fix + _typedFunctionData: { + signatures: Signature[] + signatureMap: TypedReferenceMap + } + signatures: Signature[] + createCount: number + warnAgainstDeprecatedThis?: boolean + + create: any // TODO figure out what this should be + onMismatch: OnMismatchFn + throwMismatchError: OnMismatchFn + createError: CreateErrorFn + clear: ClearFn + clearConversions: ClearConversionsFn + addTypes: AddTypesFn + _findType: FindTypeFn + referTo: ReferToFn + referToSelf: ReferToSelfFn + convert: ConvertFn + findSignature: FindSignatureFn + find: FindFn + isTypedFunction: IsTypedFunctionFn + addType: AddTypeFn + addConversion: AddConversionFn + addConversions: AddConversionsFn + removeConversion: RemoveConversionFn + resolve: ResolveFn +} + +export interface LegacyTypedFunction { + (...args: any[]): any; + signature: string; +} + +export type InitialTypedFunction = Partial & Pick + +export interface TypedReferenceToSelfCallback { + (self: TypedFunction): TypedReferenceToSelf // TODO check what self should be +} +export interface TypedReferenceToCallback { + (self: TypedReference[]): TypedReferenceTo // TODO check what self should be +} +export interface TypedReferenceToSelf { + referToSelf: { + callback: TypedReferenceToSelfCallback + } +} +export interface TypedReferenceTo { + referTo: { + callback: TypedReferenceToCallback + references: string[] // TODO ensure this is correct + } +} + +export type TypedReference = TypedReferenceToSelf | TypedReferenceTo + +export type TypedReferenceMap = Record + +export type TestFunction = (x: any) => boolean +export class TypedFunctionTypeError extends TypeError { + data: { + category: "wrongType" | "tooFewArgs" | "tooManyArgs" | "mismatch" + fn?: string + index?: number + actual?: string[] + expected?: string[] + expectedLength?: number + argument?: any + } | null = null +} + +export class TypedFunctionError extends Error { + data: { + signature?: string + actual?: string + expected?: string + sourceFunction?: Function + } | null = {} +} + +export class TypedFunctionIndexError extends Error { + data: { + index?: number + argument?: TypedFunction | LegacyTypedFunction + } | null = {} +} + +// create a new instance of typed-function +function create() { + // data type tests + + /** + * Returns true if the argument is a non-null "plain" object + */ + function isPlainObject(x: any): x is object { + return typeof x === "object" && x !== null && x.constructor === Object + } + + const _types: TypeDef[] = [ + { + name: "number", + test: function (x: any): x is number { + return typeof x === "number" + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "string", + test: function (x: any): x is string { + return typeof x === "string" + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "boolean", + test: function (x: any): x is boolean { + return typeof x === "boolean" + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "Function", + test: function (x: any): x is Function { + return isFunction(x) + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "Array", + test: Array.isArray, + conversionsTo: [] + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "Date", + test: function (x: any): x is Date { + return x instanceof Date + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "RegExp", + test: function (x: any): x is RegExp { + return x instanceof RegExp + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "Object", + test: isPlainObject, + conversionsTo: [] + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "null", + test: function (x: any): x is null { + return x === null + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + { + name: "undefined", + test: function (x: any): x is undefined { + return x === undefined + }, + conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... + }, + ] + + const anyType: TypeDef = { + name: "any", + test: ok, + isAny: true, + // conversionsTo: [], // TODO check what this should be + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be + } + + // Data structures to track the types. As these are local variables in + // create(), each typed universe will get its own copy, but the variables + // will only be accessible through the (closures of the) functions supplied + // as properties of the typed object, not directly. + // These will be initialized in clear() below + let typeMap: Record // primary store of all types + let typeList: string[] // Array of just type names, for the sake of ordering + + // And similar data structures for the type conversions: + let nConversions = 0 + // the actual conversions are stored on a property of the destination types + + // This is a temporary object, will be replaced with a function at the end + let typed: TypedFunction = { createCount: 0 } as any // TODO figure out a better way... + + /** + * Takes a type name and returns the corresponding official type object + * for that type. + */ + function findType(typeName: string): TypeDef { + const type = typeMap.get(typeName) + if (type) { + return type + } + // Remainder is error handling + let message = 'Unknown type "' + typeName + '"' + const name = typeName.toLowerCase() + let otherName + for (otherName of typeList) { + if (otherName.toLowerCase() === name) { + message += '. Did you mean "' + otherName + '" ?' + break + } + } + throw new TypeError(message) + } + + /** + * Adds an array `types` of type definitions to this typed instance. + * Each type definition should be an object with properties: + * 'name' - a string giving the name of the type; 'test' - function + * returning a boolean that tests membership in the type; and optionally + * 'isAny' - true only for the 'any' type. + * + * The second optional argument, `before`, gives the name of a type that + * these types should be added before. The new types are added in the + * order specified. + */ + function addTypes(types: TypeDef[], beforeSpec: "any" | "Object" | false = "any") { + const beforeIndex = + (beforeSpec ? findType(beforeSpec).index : typeList.length) || 0 // TODO check if right!!!!!!!! + + const newTypes = [] + + for (var i = 0; i < types.length; ++i) { + if ( + !types[i] || + typeof types[i].name !== "string" || + typeof types[i].test !== "function" + ) { + throw new TypeError( + "Object with properties {name: string, test: function} expected" + ) + } + const typeName = types[i].name + if (typeMap.has(typeName)) { + throw new TypeError('Duplicate type name "' + typeName + '"') + } + newTypes.push(typeName) + typeMap.set(typeName, { + name: typeName, + test: types[i].test, + isAny: types[i].isAny, + index: beforeIndex + i, // TODO check if this is right!!! + conversionsTo: [], // Newly added type can't have any conversions to it + }) + } + // update the typeList + const affectedTypes = typeList.slice(beforeIndex) + typeList = typeList + .slice(0, beforeIndex) + .concat(newTypes) + .concat(affectedTypes) + // Fix the indices + for (let i = beforeIndex + newTypes.length; i < typeList.length; ++i) { + typeMap.get(typeList[i]).index = i + } + } + + /** + * Removes all types and conversions from this typed instance. + * May cause previously constructed typed-functions to throw + * strange errors when they are called with types that do not + * match any of their signatures. + */ + function clear() { + typeMap = new Map() + typeList = [] + nConversions = 0 + addTypes([anyType], false) + } + + // initialize the types to the default list + clear() + addTypes(_types) + + /** + * Removes all conversions, leaving the types alone. + */ + function clearConversions() { + let typeName + for (typeName of typeList) { + typeMap.get(typeName).conversionsTo = [] + } + nConversions = 0 + } + + /** + * Find the type names that match a value. + * @return Array of names of types for which + * the type test matches the value. + */ + function findTypeNames(value: any): string[] { + const matches = typeList.filter((name) => { + const type = typeMap.get(name) + return !type.isAny && type.test(value) + }) + if (matches.length) { + return matches + } + return ["any"] + } + + /** + * Check if an entity is a typed function created by any instance + */ + function isTypedFunction(entity: any): entity is TypedFunction { + return ( + entity && isFunction(entity) && "_typedFunctionData" in entity + ) + } + + /** + * Check if an entity is a typed function created by any instance + */ + function isLegacyTypedFunction(entity: any): entity is LegacyTypedFunction { + return ( + entity && isFunction(entity) && "signature" in entity + ) + } + + /** + * Find a specific signature from a (composed) typed function, for example: + * + * typed.findSignature(fn, ['number', 'string']) + * typed.findSignature(fn, 'number, string') + * typed.findSignature(fn, 'number,string', {exact: true}) + * + * This function findSignature will by default return the best match to + * the given signature, possibly employing type conversions. + * + * The (optional) third argument is a plain object giving options + * controlling the signature search. Currently the only implemented + * option is `exact`: if specified as true (default is false), only + * exact matches will be returned (i.e. signatures for which `fn` was + * directly defined). Note that a (possibly different) type matching + * `any`, or one or more instances of TYPE matching `...TYPE` are + * considered exact matches in this regard, as no conversions are used. + * + * This function returns a "signature" object, as does `typed.resolve()`, + * which is a plain object with four keys: `params` (the array of parameters + * for this signature), `fn` (the originally supplied function for this + * signature), `test` (a generated function that determines if an argument + * list matches this signature, and `implementation` (the function to call + * on a matching argument list, that performs conversions if necessary and + * then calls the originally supplied function). + * + * @param fn A typed-function + * Signature to be found, can be an array or a comma separated string. + * @paramControls the signature search as documented + * @return Returns the matching signature, or throws an error when no signature + * is found. + */ + + function findSignature( + fn: TypedFunction, + signature: string | string[], + options?: FindSignatureOptions + ): Signature { + if (!isTypedFunction(fn)) { + throw new TypeError(NOT_TYPED_FUNCTION) + } + + // Canonicalize input + const exact = options && options.exact + const stringSignature = Array.isArray(signature) + ? signature.join(",") + : signature + const params = parseSignature(stringSignature) || [] + const canonicalSignature = stringifyParams(params) + + // First hope we get lucky and exactly match a signature + if (!exact || canonicalSignature in fn.signatures) { + // OK, we can check the internal signatures + const match = fn._typedFunctionData.signatureMap.get(canonicalSignature) + if (match) { + return match + } + } + + // Oh well, we did not; so we have to go back and check the parameters + // one by one, in order to catch things like `any` and rest params. + // Note here we can assume there is at least one parameter, because + // the empty signature would have matched successfully above. + const nParams = params.length + let remainingSignatures + if (exact) { + remainingSignatures = [] + let name + for (name in fn.signatures) { + remainingSignatures.push(fn._typedFunctionData.signatureMap.get(name)) + } + } else { + remainingSignatures = fn._typedFunctionData.signatures + } + for (var i = 0; i < nParams; ++i) { + const want = params[i] + const filteredSignatures = [] + let possibility + for (possibility of remainingSignatures) { + const have = getParamAtIndex(possibility.params, i) + if (!have || (want.restParam && !have.restParam)) { + continue + } + if (!have.hasAny) { + // have to check all of the wanted types are available + const haveTypes = paramTypeSet(have) + if (want.types.some((wtype) => !haveTypes.has(wtype.name))) { + continue + } + } + // OK, this looks good + filteredSignatures.push(possibility) + } + remainingSignatures = filteredSignatures + if (remainingSignatures.length === 0) break + } + // Return the first remaining signature that was totally matched: + let candidate + for (candidate of remainingSignatures) { + if (candidate.params.length <= nParams) { + return candidate + } + } + + throw new TypeError( + "Signature not found (signature: " + + (fn.name || "unnamed") + + "(" + + stringifyParams(params, ", ") + + "))" + ) + } + + /** + * Find the proper function to call for a specific signature from + * a (composed) typed function, for example: + * + * typed.find(fn, ['number', 'string']) + * typed.find(fn, 'number, string') + * typed.find(fn, 'number,string', {exact: true}) + * + * This function find will by default return the best match to + * the given signature, possibly employing type conversions (and returning + * a function that will perform those conversions as needed). The + * (optional) third argument is a plain object giving options contolling + * the signature search. Currently only the option `exact` is implemented, + * which defaults to "false". If `exact` is specified as true, then only + * exact matches will be returned (i.e. signatures for which `fn` was + * directly defined). Uses of `any` and `...TYPE` are considered exact if + * no conversions are necessary to apply the corresponding function. + * + * @param signature Signature to be found, can be an array or a comma separated string. + * @param Controls the signature match as documented + * @return Returns the function to call for the given signature, or throws an error if no match is found. + */ + function find( + fn: TypedFunction, + signature: string | string[], + options?: FindSignatureOptions + ) { + return findSignature(fn, signature, options).implementation + } + + /** + * Convert a given value to another data type, specified by type name. + */ + function convert(value: any, typeName: string) { + // check conversion is needed + const type = findType(typeName) + if (type.test(value)) { + return value + } + const conversions = type.conversionsTo + if (conversions.length === 0) { + throw new Error("There are no conversions to " + typeName + " defined.") + } + for (var i = 0; i < conversions.length; i++) { + const fromType = findType(conversions[i].from) + if (fromType.test(value)) { + return conversions[i].convert(value) + } + } + + throw new Error("Cannot convert " + value + " to " + typeName) + } + + /** + * Stringify parameters in a normalized way + */ + function stringifyParams(params: Param[], separator: string = ",") { + return params.map((p) => p.name).join(separator) + } + + /** + * Parse a parameter, like "...number | boolean" + */ + function parseParam(param: string): Param { + const restParam = param.indexOf("...") === 0 + const types = !restParam ? param : param.length > 3 ? param.slice(3) : "any" + + const typeDefs = types.split("|").map((s) => findType(s.trim())) + + let hasAny = false + let paramName = restParam ? "..." : "" + + const exactTypes: Type[] = typeDefs.map(function (type) { + hasAny = type.isAny || hasAny + paramName += type.name + "|" + + return { + name: type.name, + typeIndex: type.index, + test: type.test, + isAny: type.isAny, + conversion: null, + conversionIndex: -1, + typeSet: new Set(), + } + }) + + return { + types: exactTypes, + name: paramName.slice(0, -1), // remove trailing '|' from above + hasAny: hasAny, + hasConversion: false, + restParam: restParam, + // typeSet: ?? // TODO check what this shoul dbe + } + } + + /** + * Expands a parsed parameter with the types available from currently + * defined conversions. + */ + function expandParam(param: Param) { + const typeNames = param.types.map((t) => t.name) + const matchingConversions = availableConversions(typeNames) + let hasAny = param.hasAny + let newName = param.name + + const convertibleTypes = matchingConversions.map(function (conversion) { + const type = findType(conversion.from) + hasAny = type.isAny || hasAny + newName += "|" + conversion.from + + return { + name: conversion.from, + typeIndex: type.index || 0, // TODO check what to do here!!! + test: type.test, + isAny: type.isAny || false, // TODO check what to do here!!! + conversion: conversion, + conversionIndex: conversion.index, + } + }) + + return { + types: param.types.concat(convertibleTypes), + name: newName, + hasAny: hasAny, + hasConversion: convertibleTypes.length > 0, + restParam: param.restParam, + } + } + + /** + * Return the set of type names in a parameter. + * Caches the result for efficiency + */ + function paramTypeSet(param: Param): Set { + if (!param.typeSet) { + param.typeSet = new Set() + param.types.forEach((type) => param.typeSet.add(type.name)) + } + return param.typeSet + } + + /** + * Parse a signature with comma separated parameters, + * like "number | boolean, ...string" + */ + function parseSignature(rawSignature: string): Param[] | null { + const params: Param[] = [] + + if (typeof rawSignature !== "string") { + throw new TypeError("Signatures must be strings") + } + const signature = rawSignature.trim() + if (signature === "") { + return params + } + + const rawParams = signature.split(",") + for (var i = 0; i < rawParams.length; ++i) { + const parsedParam = parseParam(rawParams[i].trim()) + if (parsedParam.restParam && i !== rawParams.length - 1) { + throw new SyntaxError( + 'Unexpected rest parameter "' + + rawParams[i] + + '": ' + + "only allowed for the last parameter" + ) + } + // if invalid, short-circuit (all of the types may have been filtered) + if (parsedParam.types.length == 0) { + return null + } + params.push(parsedParam) + } + + return params + } + + /** + * Test whether a set of params contains a restParam + * @return Returns true when the last parameter is a restParam + */ + function hasRestParam(params: Param[]) { + const param = last(params) + return param ? param.restParam : false + } + + /** + * Create a type test for a single parameter, which can have one or multiple + * types. + */ + function compileTest(param: Param): TestFunction { + if (!param || param.types.length === 0) { + // nothing to do + return ok + } else if (param.types.length === 1) { + return findType(param.types[0].name).test + } else if (param.types.length === 2) { + const test0 = findType(param.types[0].name).test + const test1 = findType(param.types[1].name).test + return function or(x) { + return test0(x) || test1(x) + } + } else { + // param.types.length > 2 + const tests = param.types.map(function (type) { + return findType(type.name).test + }) + return function or(x) { + for (var i = 0; i < tests.length; i++) { + if (tests[i](x)) { + return true + } + } + return false + } + } + } + + /** + * Create a test for all parameters of a signature + */ + function compileTests(params: Param[]): TestFunction { + let tests: TestFunction[] + let test0: TestFunction + let test1: TestFunction + + if (hasRestParam(params)) { + // variable arguments like '...number' + tests = initial(params).map(compileTest) + const varIndex = tests.length + const lastTest = compileTest(last(params)) + const testRestParam = function (args: any[]) { + for (var i = varIndex; i < args.length; i++) { + if (!lastTest(args[i])) { + return false + } + } + return true + } + + return function testArgs(args) { + for (var i = 0; i < tests.length; i++) { + if (!tests[i](args[i])) { + return false + } + } + return testRestParam(args) && args.length >= varIndex + 1 + } + } else { + // no variable arguments + if (params.length === 0) { + return function testArgs(args) { + return args.length === 0 + } + } else if (params.length === 1) { + test0 = compileTest(params[0]) + return function testArgs(args) { + return test0(args[0]) && args.length === 1 + } + } else if (params.length === 2) { + test0 = compileTest(params[0]) + test1 = compileTest(params[1]) + return function testArgs(args) { + return test0(args[0]) && test1(args[1]) && args.length === 2 + } + } else { + // arguments.length > 2 + tests = params.map(compileTest) + return function testArgs(args) { + for (var i = 0; i < tests.length; i++) { + if (!tests[i](args[i])) { + return false + } + } + return args.length === tests.length + } + } + } + } + + /** + * Find the parameter at a specific index of a Params list. + * Handles rest parameters. + * @return Returns the matching parameter when found, null otherwise. + */ + function getParamAtIndex(params: Param[], index: number) { + return index < params.length + ? params[index] + : hasRestParam(params) + ? last(params) + : null + } + + /** + * Get all type names of a parameter + * @return Returns an array with type names + */ + function getTypeSetAtIndex(params: Param[], index: number) { + const param = getParamAtIndex(params, index) + if (!param) { + return new Set() + } + return paramTypeSet(param) + } + + /** + * Test whether a type is an exact type or conversion + */ + function isExactType(type: Type) { + return type.conversion === null || type.conversion === undefined + } + + /** + * Helper function for creating error messages: create an array with + * all available types on a specific argument index. + * @return Returns an array with available types + */ + function mergeExpectedParams( + signatures: Signature[], + index: number + ): string[] { + const typeSet = new Set() + signatures.forEach((signature) => { + const paramSet = getTypeSetAtIndex(signature.params, index) + let name + for (name of paramSet) { + typeSet.add(name) + } + }) + + return typeSet.has("any") ? ["any"] : Array.from(typeSet) + } + + /** + * Create + * @param name The name of the function + * @param args The actual arguments passed to the function + * @param signatures A list with available signatures + * @return Returns a type error with additional data + * attached to it in the property `data` + */ + function createError( + name: string, + args: TArg[], + signatures: Signature[] + ): TypedFunctionTypeError { + let err, expected + const _name = name || "unnamed" + + // test for wrong type at some index + let matchingSignatures = signatures + for (var index = 0; index < args.length; index++) { + const nextMatchingDefs: Signature[] = [] + matchingSignatures.forEach((signature) => { + const param = getParamAtIndex(signature.params, index) + const test = compileTest(param) // TODO check what should happen if null + if ( + (index < signature.params.length || hasRestParam(signature.params)) && + test(args[index]) + ) { + nextMatchingDefs.push(signature) + } + }) + + if (nextMatchingDefs.length === 0) { + // no matching signatures anymore, throw error "wrong type" + expected = mergeExpectedParams(matchingSignatures, index) + if (expected.length > 0) { + const actualTypes = findTypeNames(args[index]) + + err = new TypedFunctionTypeError( + "Unexpected type of argument in function " + + _name + + " (expected: " + + expected.join(" or ") + + ", actual: " + + actualTypes.join(" | ") + + ", index: " + + index + + ")" + ) + err.data = { + category: "wrongType", + fn: _name, + index: index, + actual: actualTypes, + expected: expected, + } + return err + } + } else { + matchingSignatures = nextMatchingDefs + } + } + + // test for too few arguments + const lengths = matchingSignatures.map(function (signature) { + return hasRestParam(signature.params) ? Infinity : signature.params.length + }) + if (args.length < Math.min.apply(null, lengths)) { + expected = mergeExpectedParams(matchingSignatures, index) + err = new TypedFunctionTypeError( + "Too few arguments in function " + + _name + + " (expected: " + + expected.join(" or ") + + ", index: " + + args.length + + ")" + ) + err.data = { + category: "tooFewArgs", + fn: _name, + index: args.length, + expected: expected, + } + return err + } + + // test for too many arguments + const maxLength = Math.max.apply(null, lengths) + if (args.length > maxLength) { + err = new TypedFunctionTypeError( + "Too many arguments in function " + + _name + + " (expected: " + + maxLength + + ", actual: " + + args.length + + ")" + ) + err.data = { + category: "tooManyArgs", + fn: _name, + index: args.length, + expectedLength: maxLength, + } + return err + } + + // Generic error + const argTypes = [] + for (var i = 0; i < args.length; ++i) { + argTypes.push(findTypeNames(args[i]).join("|")) + } + err = new TypedFunctionTypeError( + 'Arguments of type "' + + argTypes.join(", ") + + '" do not match any of the defined signatures of function ' + + _name + + "." + ) + err.data = { + category: "mismatch", + actual: argTypes, + } + return err + } + + /** + * Find the lowest index of all exact types of a parameter (no conversions) + * @return Returns the index of the lowest type in typed.types + */ + function getLowestTypeIndex(param: Param) { + let min = typeList.length + 1 + + for (var i = 0; i < param.types.length; i++) { + if (isExactType(param.types[i])) { + min = Math.min(min, param.types[i].typeIndex) + } + } + + return min + } + + /** + * Find the lowest index of the conversion of all types of the parameter + * having a conversion + * @return Returns the lowest index of the conversions of this type + */ + function getLowestConversionIndex(param: Param) { + let min = nConversions + 1 + + for (var i = 0; i < param.types.length; i++) { + if (!isExactType(param.types[i])) { + min = Math.min(min, param.types[i].conversionIndex) + } + } + + return min + } + + /** + * Compare two params + * @return returns -1 when param1 must get a lower index than param2, 1 when the opposite, or zero when both are equal + */ + function compareParams(param1: Param, param2: Param) { + // We compare a number of metrics on a param in turn: + // 1) 'any' parameters are the least preferred + if (param1.hasAny) { + if (!param2.hasAny) { + return 1 + } + } else if (param2.hasAny) { + return -1 + } + + // 2) Prefer non-rest to rest parameters + if (param1.restParam) { + if (!param2.restParam) { + return 1 + } + } else if (param2.restParam) { + return -1 + } + + // 3) Prefer exact type match to conversions + if (param1.hasConversion) { + if (!param2.hasConversion) { + return 1 + } + } else if (param2.hasConversion) { + return -1 + } + + // 4) Prefer lower type index: + const typeDiff = getLowestTypeIndex(param1) - getLowestTypeIndex(param2) + if (typeDiff < 0) { + return -1 + } + if (typeDiff > 0) { + return 1 + } + + // 5) Prefer lower conversion index + const convDiff = + getLowestConversionIndex(param1) - getLowestConversionIndex(param2) + if (convDiff < 0) { + return -1 + } + if (convDiff > 0) { + return 1 + } + + // Don't have a basis for preference + return 0 + } + + /** + * Compare two signatures + * @return returns a negative number when param1 must get a lower index than param2, a positive number when the opposite, or zero when both are equal + */ + function compareSignatures(signature1: Signature, signature2: Signature) { + const pars1 = signature1.params + const pars2 = signature2.params + const last1 = last(pars1) + const last2 = last(pars2) + const hasRest1 = hasRestParam(pars1) + const hasRest2 = hasRestParam(pars2) + // We compare a number of metrics on signatures in turn: + // 1) An "any rest param" is least preferred + if (hasRest1 && last1.hasAny) { + if (!hasRest2 || !last2.hasAny) { + return 1 + } + } else if (hasRest2 && last2.hasAny) { + return -1 + } + + // 2) Minimize the number of 'any' parameters + let any1 = 0 + let conv1 = 0 + let par + for (par of pars1) { + if (par.hasAny) ++any1 + if (par.hasConversion) ++conv1 + } + let any2 = 0 + let conv2 = 0 + for (par of pars2) { + if (par.hasAny) ++any2 + if (par.hasConversion) ++conv2 + } + if (any1 !== any2) { + return any1 - any2 + } + + // 3) A conversion rest param is less preferred + if (hasRest1 && last1.hasConversion) { + if (!hasRest2 || !last2.hasConversion) { + return 1 + } + } else if (hasRest2 && last2.hasConversion) { + return -1 + } + + // 4) Minimize the number of conversions + if (conv1 !== conv2) { + return conv1 - conv2 + } + + // 5) Prefer no rest param + if (hasRest1) { + if (!hasRest2) { + return 1 + } + } else if (hasRest2) { + return -1 + } + + // 6) Prefer shorter with rest param, longer without + const lengthCriterion = (pars1.length - pars2.length) * (hasRest1 ? -1 : 1) + if (lengthCriterion !== 0) { + return lengthCriterion + } + + // Signatures are identical in each of the above metrics. + // In particular, they are the same length. + // We can therefore compare the parameters one by one. + // First we count which signature has more preferred parameters. + const comparisons = [] + let tc = 0 + for (let i = 0; i < pars1.length; ++i) { + const thisComparison = compareParams(pars1[i], pars2[i]) + comparisons.push(thisComparison) + tc += thisComparison + } + if (tc !== 0) { + return tc + } + + // They have the same number of preferred parameters, so go by the + // earliest parameter in which we have a preference. + // In other words, dispatch is driven somewhat more by earlier + // parameters than later ones. + let c + for (c of comparisons) { + if (c !== 0) { + return c + } + } + + // It's a tossup: + return 0 + } + + /** + * Produce a list of all conversions from distinct types to one of + * the given types. + * @return Returns the conversions that are available + * resulting in any given type (if any) + */ + function availableConversions(typeNames: string[]): ConversionDef[] { + if (typeNames.length === 0) { + return [] + } + const types = typeNames.map(findType) + if (typeNames.length > 1) { + types.sort((t1, t2) => t1.index - t2.index) + } + let matches = types[0].conversionsTo + if (typeNames.length === 1) { + return matches + } + + matches = matches.concat([]) // shallow copy the matches + // Since the types are now in index order, we just want the first + // occurrence of any from type: + const knownTypes = new Set(typeNames) + for (var i = 1; i < types.length; ++i) { + let newMatch + for (newMatch of types[i].conversionsTo) { + if (!knownTypes.has(newMatch.from)) { + matches.push(newMatch) + knownTypes.add(newMatch.from) + } + } + } + + return matches + } + + interface PreprocessFn { + (...args: any[]): any + } + + /** + * Preprocess arguments before calling the original function: + * - if needed convert the parameters + * - in case of rest parameters, move the rest parameters into an Array + * @return Returns a wrapped function + */ + function compileArgsPreprocessing( + params: Param[], + fn: (...args: any[]) => any + ) { + let fnConvert = fn + + // TODO: can we make this wrapper function smarter/simpler? + + if (params.some((p) => p.hasConversion)) { + const restParam = hasRestParam(params) + const compiledConversions = params.map(compileArgConversion) + + fnConvert = function convertArgs(this: (args: any[]) => any) { + const args = [] + const last = restParam ? arguments.length - 1 : arguments.length + for (var i = 0; i < last; i++) { + args[i] = compiledConversions[i](arguments[i]) + } + if (restParam) { + args[last] = arguments[last].map(compiledConversions[last]) + } + + return fn.apply(this, args) + } + } + + let fnPreprocess = fnConvert + if (hasRestParam(params)) { + const offset = params.length - 1 + + fnPreprocess = function preprocessRestParams(this: PreprocessFn) { + return fnConvert.apply( + this, + slice(arguments, 0, offset).concat([slice(arguments, offset)]) + ) + } + } + + return fnPreprocess + } + + /** + * Compile conversion for a parameter to the right type + * @return Returns the wrapped function that will convert arguments + */ + function compileArgConversion(param: Param) { + let test0: TestFunction + let test1: TestFunction + let conversion0: ConversionDefConvertFunction + let conversion1: ConversionDefConvertFunction + + const tests: TestFunction[] = [] + const conversions: ConversionDefConvertFunction[] = [] + + param.types.forEach(function (type) { + if (type.conversion) { + tests.push(findType(type.conversion.from).test) + conversions.push(type.conversion.convert) + } + }) + + // create optimized conversion functions depending on the number of conversions + switch (conversions.length) { + case 0: + return function convertArg(arg: any) { + return arg + } + + case 1: + test0 = tests[0] + conversion0 = conversions[0] + return function convertArg(arg: any) { + if (test0(arg)) { + return conversion0(arg) + } + return arg + } + + case 2: + test0 = tests[0] + test1 = tests[1] + conversion0 = conversions[0] + conversion1 = conversions[1] + return function convertArg(arg: any) { + if (test0(arg)) { + return conversion0(arg) + } + if (test1(arg)) { + return conversion1(arg) + } + return arg + } + + default: + return function convertArg(arg: any) { + for (var i = 0; i < conversions.length; i++) { + if (tests[i](arg)) { + return conversions[i](arg) + } + } + return arg + } + } + } + + /** + * Split params with union types in to separate params. + * + * For example: + * + * splitParams([['Array', 'Object'], ['string', 'RegExp']) + * // returns: + * // [ + * // ['Array', 'string'], + * // ['Array', 'RegExp'], + * // ['Object', 'string'], + * // ['Object', 'RegExp'] + * // ] + */ + function splitParams(params: Param[]) { + function _splitParams( + params: Param[], + index: number, + paramsSoFar: Param[] + ): Param[][] { // TODO check if Param[][] is correct + if (index < params.length) { + const param = params[index] + let resultingParams: Param[] = [] + + if (param.restParam) { + // split the types of a rest parameter in two: + // one with only exact types, and one with exact types and conversions + const exactTypes = param.types.filter(isExactType) + if (exactTypes.length < param.types.length) { + resultingParams.push({ + types: exactTypes, + name: "..." + exactTypes.map((t) => t.name).join("|"), + hasAny: exactTypes.some((t) => t.isAny), + hasConversion: false, + restParam: true, + // typeSet: ?? // TODO check what this should be + }) + } + resultingParams.push(param) + } else { + // split all the types of a regular parameter into one type per param + resultingParams = param.types.map(function (type) { + return { + types: [type], + name: type.name, + hasAny: type.isAny, + hasConversion: !!type.conversion, // TODO check if this is correct + restParam: false, + // typeSet: ?? // TODO check what this should be + } + }) + } + + // recurse over the groups with types + return flatMap(resultingParams, function (nextParam: Param) { + return _splitParams( + params, + index + 1, + paramsSoFar.concat([nextParam]) + ) + }) + } else { + // we've reached the end of the parameters. + return [paramsSoFar] + } + } + + return _splitParams(params, 0, []) + } + + /** + * Test whether two param lists represent conflicting signatures + * @return Returns true when the signatures conflict, false otherwise. + */ + function conflicting(params1: Param[], params2: Param[]) { + const ii = Math.max(params1.length, params2.length) + + for (var i = 0; i < ii; i++) { + const typeSet1 = getTypeSetAtIndex(params1, i) + const typeSet2 = getTypeSetAtIndex(params2, i) + let overlap = false + let name + for (name of typeSet2) { + if (typeSet1.has(name)) { + overlap = true + break + } + } + if (!overlap) { + return false + } + } + + const len1 = params1.length + const len2 = params2.length + const restParam1 = hasRestParam(params1) + const restParam2 = hasRestParam(params2) + + return restParam1 + ? restParam2 + ? len1 === len2 + : len2 >= len1 + : restParam2 + ? len1 >= len2 + : len1 === len2 + } + + /** + * Helper function for `resolveReferences` that returns a copy of + * functionList with any prior resolutions cleared out, in case we are + * recycling signatures from a prior typed function construction. + */ + function clearResolutions(functionList: TypedReference[]): TypedReference[] { + return functionList.map((fn) => { + if (isReferToSelf(fn)) { + return referToSelf(fn.referToSelf.callback) + } + if (isReferTo(fn)) { + return makeReferTo(fn.referTo.references, fn.referTo.callback) + } + return fn + }) + } + + /** + * Take a list of references, a list of functions functionList, and a + * signatureMap indexing signatures into functionList, and return + * the list of resolutions, or a false-y value if they don't all + * resolve in a valid way (yet). + */ + function collectResolutions( + references: string[], + functionList: TypedReference[], + signatureMap: TypedReferenceMap + ): TypedReference[] | false { + const resolvedReferences: TypedReference[] = [] + + let reference + for (reference of references) { + let resolution = signatureMap[reference] + if (typeof resolution !== "number") { + throw new TypeError( + 'No definition for referenced signature "' + reference + '"' + ) + } + resolution = functionList[resolution] + if (typeof resolution !== "function") { + return false + } + resolvedReferences.push(resolution) + } + return resolvedReferences + } + + /** + * Resolve any references in the functionList for the typed function + * itself. The signatureMap tells which index in the functionList a + * given signature should be mapped to (for use in resolving typed.referTo) + * and self provides the destions of a typed.referToSelf. + * + * @param self The typed-function itself + * @return The list of resolved functions + */ + function resolveReferences( + functionList: TypedReference[], + signatureMap: TypedReferenceMap, + self: TypedFunction + ) { + let resolvedFunctions = clearResolutions(functionList) + let leftUnresolved = true + while (leftUnresolved) { + leftUnresolved = false + let nothingResolved = true + for (var i = 0; i < resolvedFunctions.length; ++i) { + const fn = resolvedFunctions[i] + + if (isReferToSelf(fn)) { + const newResolvedFunction = fn.referToSelf.callback(self) + resolvedFunctions[i] = newResolvedFunction + // Preserve reference in case signature is reused someday: + newResolvedFunction.referToSelf = fn.referToSelf + nothingResolved = false + } else if (isReferTo(fn)) { + const resolvedReferences = collectResolutions( + fn.referTo.references, + resolvedFunctions, + signatureMap + ) + if (resolvedReferences) { + const newResolvedFunction = fn.referTo.callback.apply( + this, // TODO figure out what this should be + resolvedReferences + ) + resolvedFunctions[i] = newResolvedFunction + // Preserve reference in case signature is reused someday: + newResolvedFunction.referTo = fn.referTo + nothingResolved = false + } else { + leftUnresolved = true + } + } + } + + if (nothingResolved && leftUnresolved) { + throw new SyntaxError( + "Circular reference detected in resolving typed.referTo" + ) + } + } + + return resolvedFunctions + } + + /** + * Validate whether any of the function bodies contains a self-reference + * usage like `this(...)` or `this.signatures`. This self-referencing is + * deprecated since typed-function v3. It has been replaced with + * the functions typed.referTo and typed.referToSelf. + */ + function validateDeprecatedThis(signaturesMap: TypedReferenceMap) { + // TODO: remove this deprecation warning logic some day (it's introduced in v3) + + // match occurrences like 'this(' and 'this.signatures' + var deprecatedThisRegex = /\bthis(\(|\.signatures\b)/ + + Object.keys(signaturesMap).forEach((signature) => { + var fn = signaturesMap[signature] + + if (deprecatedThisRegex.test(fn.toString())) { + throw new SyntaxError( + "Using `this` to self-reference a function " + + "is deprecated since typed-function@3. " + + "Use typed.referTo and typed.referToSelf instead." + ) + } + }) + } + + /** + * Create a typed function + * @param name The name for the typed function + * @param rawSignaturesMap An object with one or multiple signatures as key, and the function corresponding to the signature as value. + * @return Returns the created typed function. + */ + function createTypedFunction( + name: string, + rawSignaturesMap: TypedReferenceMap + ) { + typed.createCount++ + + if (Object.keys(rawSignaturesMap).length === 0) { + throw new SyntaxError("No signatures provided") + } + + if (typed.warnAgainstDeprecatedThis) { + validateDeprecatedThis(rawSignaturesMap) + } + + // Main processing loop for signatures + const parsedParams = [] + const originalFunctions = [] + const signaturesMap = {} + const preliminarySignatures: (PrelimianarySignature | Signature)[] = [] // may have duplicates from conversions + let signature + for (signature in rawSignaturesMap) { + // A) Protect against polluted Object prototype: + if (!Object.prototype.hasOwnProperty.call(rawSignaturesMap, signature)) { + continue + } + // B) Parse the signature + const params = parseSignature(signature) + if (!params) continue + // C) Check for conflicts + parsedParams.forEach(function (pp) { + if (conflicting(pp, params)) { + throw new TypeError( + 'Conflicting signatures "' + + stringifyParams(pp) + + '" and "' + + stringifyParams(params) + + '".' + ) + } + }) + parsedParams.push(params) + // D) Store the provided function and add conversions + const functionIndex = originalFunctions.length + originalFunctions.push(rawSignaturesMap[signature]) + const conversionParams = params.map(expandParam) + // E) Split the signatures and collect them up + let sp: Param[] + for (sp of splitParams(conversionParams)) { + const spName = stringifyParams(sp) + preliminarySignatures.push({ + params: sp, + name: spName, + fn: functionIndex, + }) + if (sp.every((p) => !p.hasConversion)) { + signaturesMap[spName] = functionIndex + } + } + } + + preliminarySignatures.sort(compareSignatures) + + // Note the forward reference to the_typed_fn + const resolvedFunctions = resolveReferences( + originalFunctions, + signaturesMap, + the_typed_fn + ) + + // Fill in the proper function for each signature + let s + for (s in signaturesMap) { + if (Object.prototype.hasOwnProperty.call(signaturesMap, s)) { + signaturesMap[s] = resolvedFunctions[signaturesMap[s]] + } + } + const signatures: Signature[] = [] + const internalSignatureMap = new Map() // benchmarks faster than object + for (s of preliminarySignatures) { + // Note it's only safe to eliminate duplicates like this + // _after_ the signature sorting step above; otherwise we might + // remove the wrong one. + if (!internalSignatureMap.has(s.name)) { + s.fn = resolvedFunctions[s.fn] + signatures.push(s) + internalSignatureMap.set(s.name, s) + } + } + + // we create a highly optimized checks for the first couple of signatures with max 2 arguments + const ok0 = + signatures[0] && + signatures[0].params.length <= 2 && + !hasRestParam(signatures[0].params) + const ok1 = + signatures[1] && + signatures[1].params.length <= 2 && + !hasRestParam(signatures[1].params) + const ok2 = + signatures[2] && + signatures[2].params.length <= 2 && + !hasRestParam(signatures[2].params) + const ok3 = + signatures[3] && + signatures[3].params.length <= 2 && + !hasRestParam(signatures[3].params) + const ok4 = + signatures[4] && + signatures[4].params.length <= 2 && + !hasRestParam(signatures[4].params) + const ok5 = + signatures[5] && + signatures[5].params.length <= 2 && + !hasRestParam(signatures[5].params) + const allOk = ok0 && ok1 && ok2 && ok3 && ok4 && ok5 + + // compile the tests + for (var i = 0; i < signatures.length; ++i) { + signatures[i].test = compileTests(signatures[i].params) + } + + const test00 = ok0 ? compileTest(signatures[0].params[0]) : notOk + const test10 = ok1 ? compileTest(signatures[1].params[0]) : notOk + const test20 = ok2 ? compileTest(signatures[2].params[0]) : notOk + const test30 = ok3 ? compileTest(signatures[3].params[0]) : notOk + const test40 = ok4 ? compileTest(signatures[4].params[0]) : notOk + const test50 = ok5 ? compileTest(signatures[5].params[0]) : notOk + + const test01 = ok0 ? compileTest(signatures[0].params[1]) : notOk + const test11 = ok1 ? compileTest(signatures[1].params[1]) : notOk + const test21 = ok2 ? compileTest(signatures[2].params[1]) : notOk + const test31 = ok3 ? compileTest(signatures[3].params[1]) : notOk + const test41 = ok4 ? compileTest(signatures[4].params[1]) : notOk + const test51 = ok5 ? compileTest(signatures[5].params[1]) : notOk + + // compile the functions + for (var i = 0; i < signatures.length; ++i) { + signatures[i].implementation = compileArgsPreprocessing( + signatures[i].params, + signatures[i].fn + ) + } + + const fn0 = ok0 ? signatures[0].implementation : undef + const fn1 = ok1 ? signatures[1].implementation : undef + const fn2 = ok2 ? signatures[2].implementation : undef + const fn3 = ok3 ? signatures[3].implementation : undef + const fn4 = ok4 ? signatures[4].implementation : undef + const fn5 = ok5 ? signatures[5].implementation : undef + + const len0 = ok0 ? signatures[0].params.length : -1 + const len1 = ok1 ? signatures[1].params.length : -1 + const len2 = ok2 ? signatures[2].params.length : -1 + const len3 = ok3 ? signatures[3].params.length : -1 + const len4 = ok4 ? signatures[4].params.length : -1 + const len5 = ok5 ? signatures[5].params.length : -1 + + // simple and generic, but also slow + const iStart = allOk ? 6 : 0 + const iEnd = signatures.length + // de-reference ahead for execution speed: + const tests = signatures.map((s) => s.test) + const fns = signatures.map((s) => s.implementation) + const generic = function generic() { + "use strict" + + for (var i = iStart; i < iEnd; i++) { + if (tests[i](arguments)) { + return fns[i].apply(this, arguments) + } + } + + return typed.onMismatch(name, arguments, signatures) + } + + // create the typed function + // fast, specialized version. Falls back to the slower, generic one if needed + function the_typed_fn(arg0: any, arg1: any) { + "use strict" + + if (arguments.length === len0 && test00(arg0) && test01(arg1)) { + return fn0.apply(this, arguments) + } + if (arguments.length === len1 && test10(arg0) && test11(arg1)) { + return fn1.apply(this, arguments) + } + if (arguments.length === len2 && test20(arg0) && test21(arg1)) { + return fn2.apply(this, arguments) + } + if (arguments.length === len3 && test30(arg0) && test31(arg1)) { + return fn3.apply(this, arguments) + } + if (arguments.length === len4 && test40(arg0) && test41(arg1)) { + return fn4.apply(this, arguments) + } + if (arguments.length === len5 && test50(arg0) && test51(arg1)) { + return fn5.apply(this, arguments) + } + + return generic.apply(this, arguments) + } + + // attach name the typed function + try { + Object.defineProperty(the_typed_fn, "name", { value: name }) + } catch (err) { + // old browsers do not support Object.defineProperty and some don't support setting the name property + // the function name is not essential for the functioning, it's mostly useful for debugging, + // so it's fine to have unnamed functions. + } + + // attach signatures to the function. + // This property is close to the original collection of signatures + // used to create the typed-function, just with unions split: + the_typed_fn.signatures = signaturesMap + + // Store internal data for functions like resolve, find, etc. + // Also serves as the flag that this is a typed-function + the_typed_fn._typedFunctionData = { + signatures: signatures, + signatureMap: internalSignatureMap, + } + + return the_typed_fn + } + + /** + * Action to take on mismatch + */ + function _onMismatch( + name: string, + args: TArg[], + signatures: Signature[] + ): never { + throw createError(name, args, signatures) + } + + /** + * Return all but the last items of an array or function Arguments + */ + function initial(arr: TItem[]): TItem[] { + return slice(arr, 0, arr.length - 1) + } + + /** + * return the last item of an array or function Arguments + */ + function last(arr: TItem[]): TItem { + return arr[arr.length - 1] + } + + /** + * Slice an array or function Arguments + */ + function slice( + arr: TItem[], + start: number | undefined, + end: number | undefined + ) { + return Array.prototype.slice.call(arr, start, end) + } + + /** + * Return the first item from an array for which test(arr[i]) returns true + * @return Returns the first matching item or undefined when there is no match + */ + function findInArray(arr: TItem[], test: (item: TItem) => boolean) { + for (var i = 0; i < arr.length; i++) { + if (test(arr[i])) { + return arr[i] + } + } + return undefined + } + + /** + * Flat map the result invoking a callback for every item in an array. + * https://gist.github.com/samgiles/762ee337dff48623e729 + */ + function flatMap( + arr: TItem[], + callback: (value: TItem, index: number, array: TItem[]) => any + ) { + return Array.prototype.concat.apply([], arr.map(callback)) + } + + /** + * Create a reference callback to one or multiple signatures + * + * Syntax: + * + * typed.referTo(signature1, signature2, ..., function callback(fn1, fn2, ...) { + * // ... + * }) + */ + function referTo(...args: Signature[]) { + let references = initial(args).map((s) => + stringifyParams(parseSignature(s)) // TODO figure out what to do when null + ) + const callback = last(args) + + if (typeof callback !== "function") { + throw new TypeError("Callback function expected as last argument") + } + + return makeReferTo(references, callback) + } + + function makeReferTo(references: string[], callback: TypedReferenceCallback) { + return { referTo: { references: references, callback: callback } } + } + + /** + * Create a reference callback to the typed-function itself + */ + function referToSelf(callback: (self: Function) => Function): TypedReference { + if (typeof callback !== "function") { + throw new TypeError("Callback function expected as first argument") + } + + return { referToSelf: { callback: callback } } + } + + function isObject(x: any): x is Object { + return typeof x === "object" + } + + function isArray(x: any): x is Array { + return Array.isArray(x) + } + + function isFunction(x: any): x is Function { + return typeof x === "function" + } + + /** + * Test whether something is a referTo object, holding a list with reference + * signatures and a callback. + */ + function isReferTo(x: any): x is TypedReferenceTo { + function hasReferToKey(x: any): x is { referTo: any } { + return 'referTo' in x + } + + function hasRefererences(x: any): x is { references: any } { + return 'references' in x + } + + function hasCallback(x: any): x is { callback: any } { + return 'callback' in x + } + + if (!x) return false + if (!hasReferToKey(x)) return false + if (!isObject(x.referTo)) return false + if (!hasRefererences(x.referTo)) return false + if (!isArray(x.referTo.references)) return false + if (!hasCallback(x.referTo)) return false + if (!isFunction(x.referTo.callback)) return false + + return true + } + + /** + * Test whether something is a referToSelf object, holding a callback where + * to pass `self`. + */ + function isReferToSelf(x: any): x is TypedReferenceToSelf { + function hasReferToSelfKey(x: any): x is { referToSelf: any } { + return 'referToSelf' in x + } + + if (!x) return false + if (!hasReferToSelfKey(x)) return false + if (!isObject(x.referToSelf)) return false + + return true + } + + /** + * Check if name is (A) new, (B) a match, or (C) a mismatch; and throw + * an error in case (C). + * @returns updated name + */ + function checkName( + nameSoFar: string | undefined, + newName: string | undefined + ) { + if (!nameSoFar) { + return newName + } + if (newName && newName != nameSoFar) { + const err = new TypedFunctionError( + "Function names do not match (expected: " + + nameSoFar + + ", actual: " + + newName + + ")" + ) + err.data = { actual: newName, expected: nameSoFar } + throw err + } + return nameSoFar + } + + /** + * Retrieve the implied name from an object with signature keys + * and function values, checking whether all value names match + */ + function getObjectName(obj: Record) { + let name + for (let key in obj) { + // Only pay attention to own properties, and only if their values + // are typed functions or functions with a signature property + if ( + obj.hasOwnProperty(key) && + (isTypedFunction(obj[key]) || isLegacyTypedFunction(obj[key])) + ) { + name = checkName(name, obj[key].name) + } + } + return name + } + + /** + * Copy all of the signatures from the second argument into the first, + * which is modified by side effect, checking for conflicts + */ + function mergeSignatures( + dest: Record, + source: Record + ) { + let key + for (key in source) { + if (source.hasOwnProperty(key)) { + if (key in dest) { + if (source[key] !== dest[key]) { + const err = new TypedFunctionError( + 'Signature "' + key + '" is defined twice' + ) + err.data = { + signature: key, + sourceFunction: source[key], + destFunction: dest[key], + } + throw err + } + // else: both signatures point to the same function, that's fine + } + dest[key] = source[key] + } + } + } + + const saveTyped = typed + /** + * Originally the main function was a typed function itself, but then + * it might not be able to generate error messages if the client + * replaced the type system with different names. + * + * Main entry: typed([name], functions/objects with signatures...) + * + * Assembles and returns a new typed-function from the given items + * that provide signatures and implementations, each of which may be + * * a plain object mapping (string) signatures to implementing functions, + * * a previously constructed typed function, or + * * any other single function with a string-valued property `signature`. + + * The name of the resulting typed-function will be given by the + * string-valued name argument if present, or if not, by the name + * of any of the arguments that have one, as long as any that do are + * consistent with each other. If no name is specified, the name will be + * an empty string. + */ + typed = function (maybeName?: any, ...args: (TypedFunction | LegacyTypedFunction)[]): TypedFunction { + const named = typeof maybeName === "string" + const start = named ? 1 : 0 + let name = named ? maybeName : "" + const allSignatures = {} + for (let i = start; i < args.length; ++i) { + const item = args[i] + let theseSignatures: Record = {} + let thisName + if (isFunction(item)) { + thisName = item.name + if (isLegacyTypedFunction(item)) { + // Case 1: Ordinary function with a string 'signature' property + theseSignatures[item.signature] = item + } else if (isTypedFunction(item)) { + // Case 2: Existing typed function + theseSignatures = item.signatures // TODO check what to do in this case. Why is `theseSignatures` now an array instead of an object? + } + } else if (isPlainObject(item)) { + // Case 3: Plain object, assume keys = signatures, values = functions + theseSignatures = item + if (!named) { + thisName = getObjectName(item) + } + } + + if (Object.keys(theseSignatures).length === 0) { + const err = new TypedFunctionIndexError( + "Argument to 'typed' at index " + + i + + " is not a (typed) function, " + + "nor an object with signatures as keys and functions as values." + ) + err.data = { index: i, argument: item } + throw err + } + + if (!named) { + name = checkName(name, thisName) // TODO check what to do when checkName returns null + } + mergeSignatures(allSignatures, theseSignatures) + } + + return createTypedFunction(name || "", allSignatures) + } + + typed.create = create + typed.createCount = saveTyped.createCount + typed.onMismatch = _onMismatch + typed.throwMismatchError = _onMismatch + typed.createError = createError + typed.clear = clear + typed.clearConversions = clearConversions + typed.addTypes = addTypes + typed._findType = findType // For unit testing only + typed.referTo = referTo + typed.referToSelf = referToSelf + typed.convert = convert + typed.findSignature = findSignature + typed.find = find + typed.isTypedFunction = isTypedFunction + typed.warnAgainstDeprecatedThis = true + + /** + * add a type (convenience wrapper for typed.addTypes) + * @param beforeObjectTest If true, the new test will be inserted before the test with name 'Object' (if any), since tests for Object match Array and classes too. + */ + typed.addType = function (type: TypeDef, beforeObjectTest = true) { + let before: "any" | "Object" = "any" + if (beforeObjectTest !== false) { + before = "Object" + } + typed.addTypes([type], before) + } + + /** + * Verify that the ConversionDef conversion has a valid format. + */ + function _validateConversion(conversion: ConversionDef) { + if ( + !conversion || + typeof conversion.from !== "string" || + typeof conversion.to !== "string" || + typeof conversion.convert !== "function" + ) { + throw new TypeError( + "Object with properties {from: string, to: string, convert: function} expected" + ) + } + if (conversion.to === conversion.from) { + throw new SyntaxError( + 'Illegal to define conversion from "' + conversion.from + '" to itself.' + ) + } + } + + /** + * Add a conversion + */ + typed.addConversion = function (conversion: ConversionDef) { + _validateConversion(conversion) + + const to = findType(conversion.to) + if ( + to.conversionsTo.every(function (other) { + return other.from !== conversion.from + }) + ) { + // TODO figure what to do with missing `to` key + to.conversionsTo.push({ + from: conversion.from, + convert: conversion.convert, + index: nConversions++, + }) + } else { + throw new Error( + 'There is already a conversion from "' + + conversion.from + + '" to "' + + to.name + + '"' + ) + } + } + + /** + * Convenience wrapper to call addConversion on each conversion in a list. + */ + typed.addConversions = function (conversions: ConversionDef[]) { + conversions.forEach(typed.addConversion) + } + + /** + * Remove the specified conversion. The format is the same as for + * addConversion, and the convert function must match or an error + * is thrown. + */ + typed.removeConversion = function (conversion: ConversionDef) { + _validateConversion(conversion) + const to = findType(conversion.to) + const existingConversion = findInArray( + to.conversionsTo, + (c) => c.from === conversion.from + ) + if (!existingConversion) { + throw new Error( + "Attempt to remove nonexistent conversion from " + + conversion.from + + " to " + + conversion.to + ) + } + if (existingConversion.convert !== conversion.convert) { + throw new Error("Conversion to remove does not match existing conversion") + } + const index = to.conversionsTo.indexOf(existingConversion) + to.conversionsTo.splice(index, 1) + } + + /** + * Produce the specific signature that a typed function + * will execute on the given arguments. Here, a "signature" is an + * object with properties 'params', 'test', 'fn', and 'implementation'. + * This last property is a function that converts params as necessary + * and then calls 'fn'. Returns null if there is no matching signature. + */ + typed.resolve = function (tf: TypedFunction, argList: any[]) { + if (!isTypedFunction(tf)) { + throw new TypeError(NOT_TYPED_FUNCTION) + } + const sigs = tf._typedFunctionData.signatures + for (var i = 0; i < sigs.length; ++i) { + if (sigs[i].test(argList)) { + return sigs[i] + } + } + return null + } + + return typed +} + +export default create