From 09b762d8579fb683b1a36774221585eed2d94c22 Mon Sep 17 00:00:00 2001 From: Matt Vague Date: Fri, 10 Jun 2022 08:31:38 -0700 Subject: [PATCH 1/6] Add TS --- package-lock.json | 2650 +-------------------------------------------- package.json | 3 +- tsconfig.json | 103 ++ 3 files changed, 112 insertions(+), 2644 deletions(-) create mode 100644 tsconfig.json 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..2afffe6 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,10 @@ "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)", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..75dcaea --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From c9989f2491e0e6383552c8ee24088519fbf104e4 Mon Sep 17 00:00:00 2001 From: Matt Vague Date: Fri, 10 Jun 2022 08:31:52 -0700 Subject: [PATCH 2/6] Switch away from IIFE --- typed-function.js | 3531 +++++++++++++++++++++++---------------------- 1 file changed, 1815 insertions(+), 1716 deletions(-) diff --git a/typed-function.js b/typed-function.js index 7684923..3c28706 100644 --- a/typed-function.js +++ b/typed-function.js @@ -5,1782 +5,1867 @@ * * 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 ok() { + return true +} + +function notOk() { + return false +} + +function undef() { + return undefined +} + +const NOT_TYPED_FUNCTION = "Argument is not a typed-function." + +// create a new instance of typed-function +function create() { + // data type tests - function notOk () { - return false; + /** + * Returns true if the argument is a non-null "plain" object + */ + function isPlainObject(x) { + return typeof x === "object" && x !== null && x.constructor === Object } - function undef () { - return undefined; + 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, } - const NOT_TYPED_FUNCTION = 'Argument is not a typed-function.' + // 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 } /** - * @typedef {{ - * params: Param[], - * fn: function, - * test: function, - * implementation: function - * }} Signature - * - * @typedef {{ - * types: Type[], - * hasAny: boolean, - * hasConversion: boolean, - * restParam: boolean - * }} Param + * Takes a type name and returns the corresponding official type object + * for that type. * - * @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 + * @param {string} typeSpec + * @returns {TypeDef} type */ - - // 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); + function findType(typeName) { + const type = typeMap.get(typeName) + if (type) { + return type } - - /** - * 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; + // 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) + } - /** - * 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); + /** + * 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); + // 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; + /** + * 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']; + /** + * 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; + /** + * 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) } - /** - * 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 } + } - // 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)) } - - // 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 } - } 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 } - 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; + // OK, this looks good + filteredSignatures.push(possibility) } - // Return the first remaining signature that was totally matched: - let candidate; - for (candidate of remainingSignatures) { - if (candidate.params.length <= nParams) { - return candidate; - } + 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; - } + throw new TypeError( + "Signature not found (signature: " + + (fn.name || "unnamed") + + "(" + + stringifyParams(params, ", ") + + "))" + ) + } - /** - * 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); - } - } + /** + * 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 + } - throw new Error('Cannot convert ' + value + ' to ' + typeName); + /** + * 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 } - - /** - * 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); + 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) + } } - /** - * 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 - }; - }); + throw new Error("Cannot convert " + value + " to " + typeName) + } - 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 - }; - }); + /** + * 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 { - types: param.types.concat(convertibleTypes), - name: newName, - hasAny: hasAny, - hasConversion: convertibleTypes.length > 0, - restParam: param.restParam - }; + 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, } + } - /** - * 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; - } + /** + * 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 - /** - * 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 convertibleTypes = matchingConversions.map(function (conversion) { + const type = findType(conversion.from) + hasAny = type.isAny || hasAny + newName += "|" + conversion.from - 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 { + 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 params; + /** + * 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 + } - /** - * 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; + /** + * 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 } - /** - * 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; + 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" + ) } - else if (param.types.length === 1) { - return findType(param.types[0].name).test; + // if invalid, short-circuit (all of the types may have been filtered) + if (parsedParam.types.length == 0) { + return null } - 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; - } + 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; } + 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; - } + /** + * 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 true + } - return function testArgs(args) { - for (var i = 0; i < tests.length; i++) { - if (!tests[i](args[i])) { - return false; - } + 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); - }; + } + return testRestParam(args) && args.length >= varIndex + 1 } - else { - // no variable arguments - if (params.length === 0) { - return function testArgs(args) { - return args.length === 0; - }; + } 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 === 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 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; - } + } 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; - }; + } + 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; - } + /** + * 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 + } - /** - * 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; + /** + * 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) + } - /** - * 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); - } - }); + /** + * Returns the name of a type + * @param {Type} type + * @return {string} Returns the type name + */ + function getTypeName(type) { + return type.name + } - return typeSet.has('any') ? ['any'] : Array.from(typeSet); - } + /** + * 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 + } - /** - * 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); - } - }); + /** + * 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) + } + }) - 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]); + return typeSet.has("any") ? ["any"] : Array.from(typeSet) + } - 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; + /** + * 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) } - } - - // 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 + }) + + 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 } - return err; + } else { + matchingSignatures = nextMatchingDefs } + } - // 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; + // 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 + } - // 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 + '.'); + // 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: 'mismatch', - actual: argTypes + category: "tooManyArgs", + fn: _name, + index: args.length, + expectedLength: maxLength, } - return err; + 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; + // 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 + } - for (var i = 0; i < param.types.length; i++) { - if (isExactType(param.types[i])) { - min = Math.min(min, param.types[i].typeIndex); - } - } + /** + * 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 - return min; + for (var i = 0; i < param.types.length; i++) { + if (isExactType(param.types[i])) { + min = Math.min(min, param.types[i].typeIndex) + } } - /** - * 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; + return min + } - for (var i = 0; i < param.types.length; i++) { - if (!isExactType(param.types[i])) { - min = Math.min(min, param.types[i].conversionIndex); - } + /** + * 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 + } - 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 } - /** - * 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 + } - // 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 + } - // 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 + } - // 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 + } - // 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 + } - // 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 } - /** - * 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 + } - // 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 + } - // 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 + } - // 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 + } - // 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 + } - // 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 + } - // 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 } + } - // 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 + } - // 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 } - /** - * 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); - } + 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; + return matches + } - // TODO: can we make this wrapper function smarter/simpler? + /** + * 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 - if (params.some(p => p.hasConversion)) { - const restParam = hasRestParam(params); - const compiledConversions = params.map(compileArgConversion); + // TODO: can we make this wrapper function smarter/simpler? - 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]); - } + if (params.some((p) => p.hasConversion)) { + const restParam = hasRestParam(params) + const compiledConversions = params.map(compileArgConversion) - return fn.apply(this, args); + 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; + 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)])); - } + 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; - } + return fnPreprocess + } - case 1: - test0 = tests[0] - conversion0 = conversions[0]; - return function convertArg(arg) { - if (test0(arg)) { - return conversion0(arg) - } - return arg; - } + /** + * 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 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; + case 1: + test0 = tests[0] + conversion0 = conversions[0] + return function convertArg(arg) { + if (test0(arg)) { + return conversion0(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; + 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 + } - /** - * 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 - }) + default: + return function convertArg(arg) { + for (var i = 0; i < conversions.length; i++) { + if (tests[i](arg)) { + return conversions[i](arg) } - 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])); - }); - + return arg } - 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; + /** + * 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, + } + }) } - if (!overlap) { - return 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] } + } - const len1 = params1.length; - const len2 = params2.length; - const restParam1 = hasRestParam(params1); - const restParam2 = hasRestParam(params2); + return _splitParams(params, 0, []) + } - return restParam1 - ? restParam2 ? (len1 === len2) : (len2 >= len1) - : restParam2 ? (len1 >= len2) : (len1 === len2) - } + /** + * 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) - /** - * 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); + 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 } - return fn; - }); + } + if (!overlap) { + return false + } } - /** - * 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); + 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) } - return resolvedReferences; + 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); + /** + * 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].referToSelf = fn.referToSelf; + resolvedFunctions[i].referTo = fn.referTo 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; - } + } else { + leftUnresolved = true } } - - if (nothingResolved && leftUnresolved) { - throw new SyntaxError( - 'Circular reference detected in resolving typed.referTo'); - } } - return resolvedFunctions; + if (nothingResolved && leftUnresolved) { + throw new SyntaxError( + "Circular reference detected in resolving typed.referTo" + ) + } } - /** - * 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) + return resolvedFunctions + } - // match occurrences like 'this(' and 'this.signatures' - var deprecatedThisRegex = /\bthis(\(|\.signatures\b)/; + /** + * 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) - Object.keys(signaturesMap).forEach(signature => { - var fn = signaturesMap[signature]; + // match occurrences like 'this(' and 'this.signatures' + var deprecatedThisRegex = /\bthis(\(|\.signatures\b)/ - 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++ + Object.keys(signaturesMap).forEach((signature) => { + var fn = signaturesMap[signature] - if (Object.keys(rawSignaturesMap).length === 0) { - throw new SyntaxError('No signatures provided'); + 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." + ) } + }) + } - if (typed.warnAgainstDeprecatedThis) { - validateDeprecatedThis(rawSignaturesMap); - } + /** + * 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; + // 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) + + '".' + ) } - // 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, }) - 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; - } + if (sp.every((p) => !p.hasConversion)) { + signaturesMap[spName] = functionIndex } } + } - preliminarySignatures.sort(compareSignatures); + preliminarySignatures.sort(compareSignatures) - // Note the forward reference to the_typed_fn - const resolvedFunctions = - resolveReferences(originalFunctions, signaturesMap, the_typed_fn); + // 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]] - } + // 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) - } + } + 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); - } + // 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 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); - } + 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'; + return typed.onMismatch(name, arguments, signatures) + } - 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); } + // create the typed function + // fast, specialized version. Falls back to the slower, generic one if needed + function the_typed_fn(arg0, arg1) { + "use strict" - return generic.apply(this, arguments); + if (arguments.length === len0 && test00(arg0) && test01(arg1)) { + return fn0.apply(this, arguments) } - - // attach name the typed function - try { - Object.defineProperty(the_typed_fn, 'name', {value: name}); + if (arguments.length === len1 && test10(arg0) && test11(arg1)) { + return fn1.apply(this, arguments) } - 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. + 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) } - // 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; + return generic.apply(this, arguments) } - /** - * 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); + // 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. } - /** - * 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); - } + // 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 - /** - * return the last item of an array or function Arguments - * @param {Array | Arguments} arr - * @return {*} - */ - function last(arr) { - return arr[arr.length - 1]; + // 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, } - /** - * 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_typed_fn + } - /** - * 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; - } + /** + * 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) + } - /** - * 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)); - } + /** + * 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) + } - /** - * 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); + /** + * return the last item of an array or function Arguments + * @param {Array | Arguments} arr + * @return {*} + */ + function last(arr) { + return arr[arr.length - 1] + } - if (typeof callback !== 'function') { - throw new TypeError('Callback function expected as last argument'); - } + /** + * 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 makeReferTo(references, callback) + /** + * 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)) + } - function makeReferTo(references, callback) { - return { referTo: { references: references, callback: 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") } - /** - * 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 makeReferTo(references, callback) + } - return { referToSelf: { callback: callback } }; - } + function makeReferTo(references, callback) { + return { referTo: { references: references, 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'; + /** + * 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") } - /** - * 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'; - } + return { referToSelf: { callback: callback } } + } - /** - * 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; + /** + * 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) - } + /** + * 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 } + 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) + } - /** - * Remove the specified conversion. The format is the same as for - * addConversion, and the convert function must match or an error - * is thrown. - * - * @param {{from: string, to: string, convert: function}} conversion - * @returns {void} - * @throws {TypeError|SyntaxError|Error} - */ - typed.removeConversion = function (conversion) { - _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. - * @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]; - } + /** + * 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 null } - return create(); -})); + return typed +} From 6c518701080fade6dffbfc0b820bbeef2af2e3f8 Mon Sep 17 00:00:00 2001 From: Matt Vague Date: Wed, 15 Jun 2022 08:49:52 -0700 Subject: [PATCH 3/6] WIP Start conversion of typed-function to typescript --- typed-function.js => typed-function.ts | 430 +++++++++++++------------ 1 file changed, 228 insertions(+), 202 deletions(-) rename typed-function.js => typed-function.ts (86%) diff --git a/typed-function.js b/typed-function.ts similarity index 86% rename from typed-function.js rename to typed-function.ts index 3c28706..15b5421 100644 --- a/typed-function.js +++ b/typed-function.ts @@ -20,6 +20,85 @@ function undef() { const NOT_TYPED_FUNCTION = "Argument is not a typed-function." +export type Signature = { + params: Param[] + fn: () => void // TODO fix + test: (x: any) => boolean + implementation: () => void // TODO fix +} + +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 + 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: any[] // TODO +} + +export interface TypedFunction { + (...args: any[]): any // TODO fix + _typedFunctionData: any + signatures: Signature[] +} + +export interface TypedReference { + referToSelf: { + callback: (self: Function) => Function // TODO figure out + } + referTo: { + callback: (self: Function) => Function // TODO figure out + references: any[] // TODO figure out + } +} + +export type TestFunction = (x: any) => boolean + +class TypedFunctionTypeError extends TypeError { + data: { + category: "wrongType" | 'tooFewArgs' | 'tooManyArgs' | 'mismatch' + fn?: string + index?: number + actual?: string[] + expected?: string[] + expectedLength?: number + } | null = null +} + +class TypedFunctionError extends Error { + data: { + signature?: string + actual?: string + expected?: string + } | null = {} +} + // create a new instance of typed-function function create() { // data type tests @@ -27,67 +106,76 @@ function create() { /** * Returns true if the argument is a non-null "plain" object */ - function isPlainObject(x) { + function isPlainObject(x: any): x is object { return typeof x === "object" && x !== null && x.constructor === Object } - const _types = [ + const _types: TypeDef[] = [ { name: "number", - test: function (x) { + test: function (x: any): x is number { return typeof x === "number" }, + conversionsTo: [], }, { name: "string", - test: function (x) { + test: function (x: any): x is string { return typeof x === "string" }, + conversionsTo: [], }, { name: "boolean", - test: function (x) { + test: function (x: any): x is boolean { return typeof x === "boolean" }, + conversionsTo: [], }, { name: "Function", - test: function (x) { + test: function (x: any): x is Function { return typeof x === "function" }, + conversionsTo: [], }, - { name: "Array", test: Array.isArray }, + { name: "Array", test: Array.isArray, conversionsTo: [] }, { name: "Date", - test: function (x) { + test: function (x: any): x is Date { return x instanceof Date }, + conversionsTo: [], }, { name: "RegExp", - test: function (x) { + test: function (x: any): x is RegExp { return x instanceof RegExp }, + conversionsTo: [], }, - { name: "Object", test: isPlainObject }, + { name: "Object", test: isPlainObject, conversionsTo: [] }, { name: "null", - test: function (x) { + test: function (x: any): x is null { return x === null }, + conversionsTo: [], }, { name: "undefined", - test: function (x) { + test: function (x: any): x is undefined { return x === undefined }, + conversionsTo: [], }, ] - const anyType = { + const anyType: TypeDef = { name: "any", test: ok, isAny: true, + conversionsTo: [], // TODO check if this is right!!! } // Data structures to track the types. As these are local variables in @@ -95,8 +183,8 @@ function create() { // 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 + let typeMap: Record // primary store of all types + let typeList: any[] // Array of just type names, for the sake of ordering // And similar data structures for the type conversions: let nConversions = 0 @@ -108,11 +196,8 @@ function create() { /** * Takes a type name and returns the corresponding official type object * for that type. - * - * @param {string} typeSpec - * @returns {TypeDef} type */ - function findType(typeName) { + function findType(typeName: string): TypeDef { const type = typeMap.get(typeName) if (type) { return type @@ -140,14 +225,13 @@ function create() { * 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 + function addTypes(types: TypeDef[], beforeSpec: "any" | 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] || @@ -167,7 +251,7 @@ function create() { name: typeName, test: types[i].test, isAny: types[i].isAny, - index: beforeIndex + i, + index: beforeIndex + i, // TODO check if this is right!!! conversionsTo: [], // Newly added type can't have any conversions to it }) } @@ -178,7 +262,7 @@ function create() { .concat(newTypes) .concat(affectedTypes) // Fix the indices - for (var i = beforeIndex + newTypes.length; i < typeList.length; ++i) { + for (let i = beforeIndex + newTypes.length; i < typeList.length; ++i) { typeMap.get(typeList[i]).index = i } } @@ -213,11 +297,10 @@ function create() { /** * Find the type names that match a value. - * @param {*} value - * @return {string[]} Array of names of types for which + * @return Array of names of types for which * the type test matches the value. */ - function findTypeNames(value) { + function findTypeNames(value: any): string[] { const matches = typeList.filter((name) => { const type = typeMap.get(name) return !type.isAny && type.test(value) @@ -230,10 +313,8 @@ function create() { /** * Check if an entity is a typed function created by any instance - * @param {any} entity - * @returns {boolean} */ - function isTypedFunction(entity) { + function isTypedFunction(entity: any): entity is TypedFunction { return ( entity && typeof entity === "function" && "_typedFunctionData" in entity ) @@ -265,25 +346,30 @@ function create() { * 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 + * @param fn A typed-function * 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 + * @paramControls the signature search as documented + * @return Returns the matching signature, or throws an error when no signature * is found. */ - function findSignature(fn, signature, exactSpec) { + + type FindSignatureOptions = { exact: boolean } + + function findSignature( + fn: TypedFunction, + signature: string | string[], + options?: FindSignatureOptions + ): Signature { if (!isTypedFunction(fn)) { throw new TypeError(NOT_TYPED_FUNCTION) } // Canonicalize input - const exact = exactSpec && exactSpec.exact + const exact = options && options.exact const stringSignature = Array.isArray(signature) ? signature.join(",") : signature - const params = parseSignature(stringSignature) + const params = parseSignature(stringSignature) || [] const canonicalSignature = stringifyParams(params) // First hope we get lucky and exactly match a signature @@ -367,25 +453,22 @@ function create() { * 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. + * @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, signature, exact) { - return findSignature(fn, signature, exact).implementation + 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. - * - * @param {*} value - * @param {string} type */ - function convert(value, typeName) { + function convert(value: any, typeName: string) { // check conversion is needed const type = findType(typeName) if (type.test(value)) { @@ -407,20 +490,15 @@ function create() { /** * Stringify parameters in a normalized way - * @param {Param[]} params - * @param {string} [','] separator - * @return {string} */ - function stringifyParams(params, separator = ",") { + function stringifyParams(params: Param[], separator: string = ",") { return params.map((p) => p.name).join(separator) } /** * Parse a parameter, like "...number | boolean" - * @param {string} param - * @return {Param} param */ - function parseParam(param) { + function parseParam(param: string): Param { const restParam = param.indexOf("...") === 0 const types = !restParam ? param : param.length > 3 ? param.slice(3) : "any" @@ -440,6 +518,7 @@ function create() { isAny: type.isAny, conversion: null, conversionIndex: -1, + typeSet: new Set(), } }) @@ -455,10 +534,8 @@ function create() { /** * Expands a parsed parameter with the types available from currently * defined conversions. - * @param {Param} param - * @return {Param} param */ - function expandParam(param) { + function expandParam(param: Param) { const typeNames = param.types.map((t) => t.name) const matchingConversions = availableConversions(typeNames) let hasAny = param.hasAny @@ -471,9 +548,9 @@ function create() { return { name: conversion.from, - typeIndex: type.index, + typeIndex: type.index || 0, // TODO check what to do here!!! test: type.test, - isAny: type.isAny, + isAny: type.isAny || false, // TODO check what to do here!!! conversion: conversion, conversionIndex: conversion.index, } @@ -491,11 +568,8 @@ function create() { /** * Return the set of type names in a parameter. * Caches the result for efficiency - * - * @param {Param} param - * @return {Set} typenames */ - function paramTypeSet(param) { + function paramTypeSet(param: Param): Set { if (!param.typeSet) { param.typeSet = new Set() param.types.forEach((type) => param.typeSet.add(type.name)) @@ -506,12 +580,10 @@ function create() { /** * Parse a signature with comma separated parameters, * like "number | boolean, ...string" - * - * @param {string} signature - * @return {Param[]} params */ - function parseSignature(rawSignature) { - const params = [] + function parseSignature(rawSignature: string): Param[] | null { + const params: Param[] = [] + if (typeof rawSignature !== "string") { throw new TypeError("Signatures must be strings") } @@ -543,10 +615,9 @@ function create() { /** * Test whether a set of params contains a restParam - * @param {Param[]} params - * @return {boolean} Returns true when the last parameter is a restParam + * @return Returns true when the last parameter is a restParam */ - function hasRestParam(params) { + function hasRestParam(params: Param[]) { const param = last(params) return param ? param.restParam : false } @@ -557,7 +628,7 @@ function create() { * @param {Param} param * @return {function(x: *) : boolean} Returns a test function */ - function compileTest(param) { + function compileTest(param: Param): TestFunction { if (!param || param.types.length === 0) { // nothing to do return ok @@ -587,11 +658,11 @@ function create() { /** * Create a test for all parameters of a signature - * @param {Param[]} params - * @return {function(args: Array<*>) : boolean} */ - function compileTests(params) { - let tests, test0, test1 + function compileTests(params: Param[]): TestFunction { + let tests: TestFunction[] + let test0: TestFunction + let test1: TestFunction if (hasRestParam(params)) { // variable arguments like '...number' @@ -650,12 +721,10 @@ function create() { /** * 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, + * @return Returns the matching parameter when found, * null otherwise. */ - function getParamAtIndex(params, index) { + function getParamAtIndex(params: Param[], index: number) { return index < params.length ? params[index] : hasRestParam(params) @@ -665,45 +734,30 @@ function create() { /** * Get all type names of a parameter - * @param {Params[]} params - * @param {number} index - * @return {string[]} Returns an array with type names + * @return Returns an array with type names */ - function getTypeSetAtIndex(params, index) { + function getTypeSetAtIndex(params: Param[], index: number) { const param = getParamAtIndex(params, index) if (!param) { - return new Set() + 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) { + 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. - * @param {Signature[]} signatures - * @param {number} index - * @return {string[]} Returns an array with available types + * @return Returns an array with available types */ - function mergeExpectedParams(signatures, index) { - const typeSet = new Set() + function mergeExpectedParams(signatures: Signature[], index: number): string[] { + const typeSet = new Set() signatures.forEach((signature) => { const paramSet = getTypeSetAtIndex(signature.params, index) let name @@ -717,20 +771,24 @@ function create() { /** * 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 + * @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, args, signatures) { + function createError( + name: string, + args: any[], + 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 = [] + const nextMatchingDefs: Signature[] = [] matchingSignatures.forEach((signature) => { const param = getParamAtIndex(signature.params, index) const test = compileTest(param) @@ -748,7 +806,7 @@ function create() { if (expected.length > 0) { const actualTypes = findTypeNames(args[index]) - err = new TypeError( + err = new TypedFunctionTypeError( "Unexpected type of argument in function " + _name + " (expected: " + @@ -779,7 +837,7 @@ function create() { }) if (args.length < Math.min.apply(null, lengths)) { expected = mergeExpectedParams(matchingSignatures, index) - err = new TypeError( + err = new TypedFunctionTypeError( "Too few arguments in function " + _name + " (expected: " + @@ -800,7 +858,7 @@ function create() { // test for too many arguments const maxLength = Math.max.apply(null, lengths) if (args.length > maxLength) { - err = new TypeError( + err = new TypedFunctionTypeError( "Too many arguments in function " + _name + " (expected: " + @@ -823,7 +881,7 @@ function create() { for (var i = 0; i < args.length; ++i) { argTypes.push(findTypeNames(args[i]).join("|")) } - err = new TypeError( + err = new TypedFunctionTypeError( 'Arguments of type "' + argTypes.join(", ") + '" do not match any of the defined signatures of function ' + @@ -839,10 +897,9 @@ function create() { /** * 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 + * @return Returns the index of the lowest type in typed.types */ - function getLowestTypeIndex(param) { + function getLowestTypeIndex(param: Param) { let min = typeList.length + 1 for (var i = 0; i < param.types.length; i++) { @@ -857,10 +914,9 @@ function create() { /** * 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) { + function getLowestConversionIndex(param: Param) { let min = nConversions + 1 for (var i = 0; i < param.types.length; i++) { @@ -874,13 +930,9 @@ function create() { /** * 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 + * @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, param2) { + 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) { @@ -934,13 +986,9 @@ function create() { /** * 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 + * @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, signature2) { + function compareSignatures(signature1: Signature, signature2: Signature) { const pars1 = signature1.params const pars2 = signature2.params const last1 = last(pars1) @@ -1037,12 +1085,10 @@ function create() { /** * 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 + * @return Returns the conversions that are available * resulting in any given type (if any) */ - function availableConversions(typeNames) { + function availableConversions(typeNames: string[]): ConversionDef[] { if (typeNames.length === 0) { return [] } @@ -1076,11 +1122,9 @@ function create() { * 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 + * @return Returns a wrapped function */ - function compileArgsPreprocessing(params, fn) { + function compileArgsPreprocessing(params: Param[], fn: () => any) { let fnConvert = fn // TODO: can we make this wrapper function smarter/simpler? @@ -1124,10 +1168,14 @@ function create() { * @return {function} Returns the wrapped function that will convert arguments * */ - function compileArgConversion(param) { - let test0, test1, conversion0, conversion1 - const tests = [] - const conversions = [] + 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) { @@ -1139,14 +1187,14 @@ function create() { // create optimized conversion functions depending on the number of conversions switch (conversions.length) { case 0: - return function convertArg(arg) { + return function convertArg(arg: any) { return arg } case 1: test0 = tests[0] conversion0 = conversions[0] - return function convertArg(arg) { + return function convertArg(arg: any) { if (test0(arg)) { return conversion0(arg) } @@ -1158,7 +1206,7 @@ function create() { test1 = tests[1] conversion0 = conversions[0] conversion1 = conversions[1] - return function convertArg(arg) { + return function convertArg(arg: any) { if (test0(arg)) { return conversion0(arg) } @@ -1169,7 +1217,7 @@ function create() { } default: - return function convertArg(arg) { + return function convertArg(arg: any) { for (var i = 0; i < conversions.length; i++) { if (tests[i](arg)) { return conversions[i](arg) @@ -1193,12 +1241,9 @@ function create() { * // ['Object', 'string'], * // ['Object', 'RegExp'] * // ] - * - * @param {Param[]} params - * @return {Param[]} */ - function splitParams(params) { - function _splitParams(params, index, paramsSoFar) { + function splitParams(params: Param[]) { + function _splitParams(params: Param[], index: number, paramsSoFar: Param[]) { if (index < params.length) { const param = params[index] let resultingParams = [] @@ -1231,7 +1276,7 @@ function create() { } // recurse over the groups with types - return flatMap(resultingParams, function (nextParam) { + return flatMap(resultingParams, function (nextParam: Param) { return _splitParams( params, index + 1, @@ -1249,11 +1294,9 @@ function create() { /** * Test whether two param lists represent conflicting signatures - * @param {Param[]} params1 - * @param {Param[]} params2 - * @return {boolean} Returns true when the signatures conflict, false otherwise. + * @return Returns true when the signatures conflict, false otherwise. */ - function conflicting(params1, params2) { + function conflicting(params1: Param[], params2: Param[]) { const ii = Math.max(params1.length, params2.length) for (var i = 0; i < ii; i++) { @@ -1294,7 +1337,7 @@ function create() { * @param {Array.} functionList * @return {Array.} */ - function clearResolutions(functionList) { + function clearResolutions(functionList: TypedReference[]) { return functionList.map((fn) => { if (isReferToSelf(fn)) { return referToSelf(fn.referToSelf.callback) @@ -1311,14 +1354,10 @@ function create() { * 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 = [] + function collectResolutions(references: string[], functionList: TypedReference[], signatureMap: Record): TypedReference[] | false { + const resolvedReferences: TypedReference[] = [] + let reference for (reference of references) { let resolution = signatureMap[reference] @@ -1342,12 +1381,10 @@ function create() { * 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 + * @param self The typed-function itself + * @return The list of resolved functions */ - function resolveReferences(functionList, signatureMap, self) { + function resolveReferences(functionList: TypedReference[], signatureMap: Record, self: TypedFunction) { let resolvedFunctions = clearResolutions(functionList) let leftUnresolved = true while (leftUnresolved) { @@ -1750,7 +1787,7 @@ function create() { * @param {(self: function) => function} callback * @returns {{referToSelf: { callback: function }}} */ - function referToSelf(callback) { + function referToSelf(callback: (self: Function) => Function): TypedReference { if (typeof callback !== "function") { throw new TypeError("Callback function expected as first argument") } @@ -1777,32 +1814,26 @@ function create() { /** * 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" - ) + function isReferToSelf(objectOrFn: { referToSelf: { callback: any } | Object }) { + if (!objectOrFn) return false + + if (typeof objectOrFn.referToSelf === "object") return true + + return false } /** * 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 + * @returns updated name */ - function checkName(nameSoFar, newName) { + function checkName(nameSoFar: string | undefined, newName: string | undefined) { if (!nameSoFar) { return newName } if (newName && newName != nameSoFar) { - const err = new Error( + const err = new TypedFunctionError( "Function names do not match (expected: " + nameSoFar + ", actual: " + @@ -1821,7 +1852,7 @@ function create() { * * @param { {string: function} } obj */ - function getObjectName(obj) { + function getObjectName(obj: Record) { let name for (let key in obj) { // Only pay attention to own properties, and only if their values @@ -1839,17 +1870,14 @@ function create() { /** * Copy all of the signatures from the second argument into the first, * which is modified by side effect, checking for conflicts - * - * @param {Object., source: Record) { let key for (key in source) { if (source.hasOwnProperty(key)) { if (key in dest) { if (source[key] !== dest[key]) { - const err = new Error('Signature "' + key + '" is defined twice') + const err = new TypedFunctionError('Signature "' + key + '" is defined twice') err.data = { signature: key, sourceFunction: source[key], @@ -1883,12 +1911,8 @@ function create() { * 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. - * - * @param {string} name [optional] - * @param {(function|object)[]} signature providers - * @returns {typed-function} */ - typed = function (maybeName) { + typed = function (maybeName?: any): TypedFunction { const named = typeof maybeName === "string" const start = named ? 1 : 0 let name = named ? maybeName : "" @@ -2091,3 +2115,5 @@ function create() { return typed } + +export default create From 4759240920e65622bffcf4c386246a1def3118fb Mon Sep 17 00:00:00 2001 From: Matt Vague Date: Wed, 15 Jun 2022 08:58:37 -0700 Subject: [PATCH 4/6] Setup TS for CI, build, etc --- .github/workflows/ci-test.yaml | 1 + package.json | 3 +- tsconfig.json | 119 ++++++++------------------------- 3 files changed, 32 insertions(+), 91 deletions(-) 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.json b/package.json index 2afffe6..518bec9 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,9 @@ "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 index 75dcaea..d497ac1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,103 +1,42 @@ { "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + "target": "es2016", /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + "module": "commonjs", + "rootDir": "./", + "moduleResolution": "node", + "baseUrl": "./", /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + "declaration": true, + "outFile": "./typed-function.js", /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "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 } } From 4479ad89d67e058542f707de0ecf8eb2a26bbf6b Mon Sep 17 00:00:00 2001 From: Matt Vague Date: Wed, 15 Jun 2022 09:26:18 -0700 Subject: [PATCH 5/6] Continue TS migration --- typed-function.ts | 242 +++++++++++++++++++++++++--------------------- 1 file changed, 131 insertions(+), 111 deletions(-) diff --git a/typed-function.ts b/typed-function.ts index 15b5421..af4dc2d 100644 --- a/typed-function.ts +++ b/typed-function.ts @@ -66,6 +66,19 @@ export interface TypedFunction { (...args: any[]): any // TODO fix _typedFunctionData: any signatures: Signature[] + createCount: number +} + +export interface TypedFunction { + (...args: any[]): any // TODO fix + _typedFunctionData: any + signatures: Signature[] + createCount: number +} + +export interface LegacyTypedFunction { + (...args: any[]): any; + signature: string; } export interface TypedReference { @@ -78,11 +91,12 @@ export interface TypedReference { } } -export type TestFunction = (x: any) => boolean +export type TypedReferenceMap = Record -class TypedFunctionTypeError extends TypeError { +export type TestFunction = (x: any) => boolean +export class TypedFunctionTypeError extends TypeError { data: { - category: "wrongType" | 'tooFewArgs' | 'tooManyArgs' | 'mismatch' + category: "wrongType" | "tooFewArgs" | "tooManyArgs" | "mismatch" fn?: string index?: number actual?: string[] @@ -91,7 +105,7 @@ class TypedFunctionTypeError extends TypeError { } | null = null } -class TypedFunctionError extends Error { +export class TypedFunctionError extends Error { data: { signature?: string actual?: string @@ -135,7 +149,7 @@ function create() { { name: "Function", test: function (x: any): x is Function { - return typeof x === "function" + return isFunction(x) }, conversionsTo: [], }, @@ -191,7 +205,7 @@ function create() { // 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 } + let typed: TypedFunction = { createCount: 0 } /** * Takes a type name and returns the corresponding official type object @@ -316,7 +330,16 @@ function create() { */ function isTypedFunction(entity: any): entity is TypedFunction { return ( - entity && typeof entity === "function" && "_typedFunctionData" in entity + entity && isFunction(y) && "_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 ) } @@ -625,8 +648,6 @@ function create() { /** * 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: Param): TestFunction { if (!param || param.types.length === 0) { @@ -669,7 +690,7 @@ function create() { tests = initial(params).map(compileTest) const varIndex = tests.length const lastTest = compileTest(last(params)) - const testRestParam = function (args) { + const testRestParam = function (args: any[]) { for (var i = varIndex; i < args.length; i++) { if (!lastTest(args[i])) { return false @@ -721,8 +742,7 @@ function create() { /** * Find the parameter at a specific index of a Params list. * Handles rest parameters. - * @return Returns the matching parameter when found, - * null otherwise. + * @return Returns the matching parameter when found, null otherwise. */ function getParamAtIndex(params: Param[], index: number) { return index < params.length @@ -756,7 +776,10 @@ function create() { * all available types on a specific argument index. * @return Returns an array with available types */ - function mergeExpectedParams(signatures: Signature[], index: number): string[] { + function mergeExpectedParams( + signatures: Signature[], + index: number + ): string[] { const typeSet = new Set() signatures.forEach((signature) => { const paramSet = getTypeSetAtIndex(signature.params, index) @@ -777,9 +800,9 @@ function create() { * @return Returns a type error with additional data * attached to it in the property `data` */ - function createError( + function createError( name: string, - args: any[], + args: TArg[], signatures: Signature[] ): TypedFunctionTypeError { let err, expected @@ -914,7 +937,7 @@ function create() { /** * Find the lowest index of the conversion of all types of the parameter * having a conversion - * @return {number} Returns the lowest index of the conversions of this type + * @return Returns the lowest index of the conversions of this type */ function getLowestConversionIndex(param: Param) { let min = nConversions + 1 @@ -1118,13 +1141,20 @@ function create() { return matches } + interface CompileFn { + compileArgsPreprocessing(): 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: () => any) { + function compileArgsPreprocessing( + params: Param[], + fn: (...args: any[]) => any + ) { let fnConvert = fn // TODO: can we make this wrapper function smarter/simpler? @@ -1133,7 +1163,7 @@ function create() { const restParam = hasRestParam(params) const compiledConversions = params.map(compileArgConversion) - fnConvert = function convertArgs() { + fnConvert = function convertArgs(this: (args: any[]) => any) { const args = [] const last = restParam ? arguments.length - 1 : arguments.length for (var i = 0; i < last; i++) { @@ -1164,9 +1194,7 @@ function create() { /** * Compile conversion for a parameter to the right type - * @param {Param} param - * @return {function} Returns the wrapped function that will convert arguments - * + * @return Returns the wrapped function that will convert arguments */ function compileArgConversion(param: Param) { let test0: TestFunction @@ -1243,7 +1271,11 @@ function create() { * // ] */ function splitParams(params: Param[]) { - function _splitParams(params: Param[], index: number, paramsSoFar: Param[]) { + function _splitParams( + params: Param[], + index: number, + paramsSoFar: Param[] + ) { if (index < params.length) { const param = params[index] let resultingParams = [] @@ -1333,9 +1365,6 @@ function create() { * 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: TypedReference[]) { return functionList.map((fn) => { @@ -1355,7 +1384,11 @@ function create() { * 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: Record): TypedReference[] | false { + function collectResolutions( + references: string[], + functionList: TypedReference[], + signatureMap: TypedReferenceMap + ): TypedReference[] | false { const resolvedReferences: TypedReference[] = [] let reference @@ -1381,10 +1414,14 @@ function create() { * 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 + * @param self The typed-function itself * @return The list of resolved functions */ - function resolveReferences(functionList: TypedReference[], signatureMap: Record, self: TypedFunction) { + function resolveReferences( + functionList: TypedReference[], + signatureMap: TypedReferenceMap, + self: TypedFunction + ) { let resolvedFunctions = clearResolutions(functionList) let leftUnresolved = true while (leftUnresolved) { @@ -1433,9 +1470,8 @@ function create() { * 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) { + function validateDeprecatedThis(signaturesMap: TypedReferenceMap) { // TODO: remove this deprecation warning logic some day (it's introduced in v3) // match occurrences like 'this(' and 'this.signatures' @@ -1456,15 +1492,14 @@ function create() { /** * 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. + * @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, rawSignaturesMap) { + function createTypedFunction( + name: string, + rawSignaturesMap: TypedReferenceMap + ) { typed.createCount++ if (Object.keys(rawSignaturesMap).length === 0) { @@ -1689,51 +1724,45 @@ function create() { /** * 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) { + function _onMismatch( + name: string, + args: TArg[], + signatures: Signature[] + ) { 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) { + function initial(arr: TItem[]): TItem[] { 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) { + function last(arr: TItem[]): TItem { 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) { + 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 - * @param {Array} arr - * @param {function} test - * @return {* | undefined} Returns the first matching item - * or undefined when there is no match + * @return Returns the first matching item or undefined when there is no match */ - function findInArray(arr, test) { + function findInArray(arr: TItem[], test: (item: TItem) => boolean) { for (var i = 0; i < arr.length; i++) { if (test(arr[i])) { return arr[i] @@ -1745,11 +1774,11 @@ function create() { /** * 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) { + function flatMap( + arr: TItem[], + callback: (value: TItem, index: number, array: TItem[]) => any + ) { return Array.prototype.concat.apply([], arr.map(callback)) } @@ -1783,9 +1812,6 @@ function create() { /** * Create a reference callback to the typed-function itself - * - * @param {(self: function) => function} callback - * @returns {{referToSelf: { callback: function }}} */ function referToSelf(callback: (self: Function) => Function): TypedReference { if (typeof callback !== "function") { @@ -1795,19 +1821,28 @@ function create() { 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. - * - * @param {Object | function} objectOrFn - * @returns {boolean} */ - function isReferTo(objectOrFn) { + function isReferTo(objectOrFn: TypedReference) { return ( objectOrFn && - typeof objectOrFn.referTo === "object" && - Array.isArray(objectOrFn.referTo.references) && - typeof objectOrFn.referTo.callback === "function" + isObject(objectOrFn.referTo) && + isArray(objectOrFn.referTo.references) && + isFunction(objectOrFn.referTo.callback) ) } @@ -1815,7 +1850,9 @@ function create() { * Test whether something is a referToSelf object, holding a callback where * to pass `self`. */ - function isReferToSelf(objectOrFn: { referToSelf: { callback: any } | Object }) { + function isReferToSelf(objectOrFn: { + referToSelf: { callback: any } | Object + }) { if (!objectOrFn) return false if (typeof objectOrFn.referToSelf === "object") return true @@ -1828,7 +1865,10 @@ function create() { * an error in case (C). * @returns updated name */ - function checkName(nameSoFar: string | undefined, newName: string | undefined) { + function checkName( + nameSoFar: string | undefined, + newName: string | undefined + ) { if (!nameSoFar) { return newName } @@ -1849,17 +1889,15 @@ function create() { /** * 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: Record) { + 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]) || typeof obj[key].signature === "string") + (isTypedFunction(obj[key]) || isLegacyTypedFunction(obj[key])) ) { name = checkName(name, obj[key].name) } @@ -1871,13 +1909,18 @@ function create() { * 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) { + 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') + const err = new TypedFunctionError( + 'Signature "' + key + '" is defined twice' + ) err.data = { signature: key, sourceFunction: source[key], @@ -1921,7 +1964,7 @@ function create() { const item = arguments[i] let theseSignatures = {} let thisName - if (typeof item === "function") { + if (isFunction(m)) { thisName = item.name if (typeof item.signature === "string") { // Case 1: Ordinary function with a string 'signature' property @@ -1977,13 +2020,9 @@ function create() { /** * add a type (convenience wrapper for typed.addTypes) - * @param {{name: string, test: function}} type - * @param {boolean} [beforeObjectTest=true] - * 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. + * @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, beforeObjectTest) { + typed.addType = function (type: Signature, beforeObjectTest = true) { let before = "any" if (beforeObjectTest !== false) { before = "Object" @@ -1993,12 +2032,8 @@ function create() { /** * Verify that the ConversionDef conversion has a valid format. - * - * @param {conversionDef} conversion - * @return {void} - * @throws {TypeError|SyntaxError} */ - function _validateConversion(conversion) { + function _validateConversion(conversion: ConversionDef) { if ( !conversion || typeof conversion.from !== "string" || @@ -2018,12 +2053,8 @@ function create() { /** * Add a conversion - * - * @param {ConversionDef} conversion - * @returns {void} - * @throws {TypeError} */ - typed.addConversion = function (conversion) { + typed.addConversion = function (conversion: ConversionDef) { _validateConversion(conversion) const to = findType(conversion.to) @@ -2050,12 +2081,8 @@ function create() { /** * Convenience wrapper to call addConversion on each conversion in a list. - * - @param {ConversionDef[]} conversions - @returns {void} - @throws {TypeError} */ - typed.addConversions = function (conversions) { + typed.addConversions = function (conversions: ConversionDef[]) { conversions.forEach(typed.addConversion) } @@ -2063,12 +2090,8 @@ function create() { * Remove the specified conversion. The format is the same as for * addConversion, and the convert function must match or an error * is thrown. - * - * @param {{from: string, to: string, convert: function}} conversion - * @returns {void} - * @throws {TypeError|SyntaxError|Error} */ - typed.removeConversion = function (conversion) { + typed.removeConversion = function (conversion: ConversionDef) { _validateConversion(conversion) const to = findType(conversion.to) const existingConversion = findInArray( @@ -2096,11 +2119,8 @@ function create() { * 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) { + typed.resolve = function (tf: TypedFunction, argList: any[]) { if (!isTypedFunction(tf)) { throw new TypeError(NOT_TYPED_FUNCTION) } From d1dcac84754d65abbd35ca2c4cedcb5aa4a54f4b Mon Sep 17 00:00:00 2001 From: Matt Vague Date: Wed, 15 Jun 2022 10:48:27 -0700 Subject: [PATCH 6/6] Continue TS migration --- typed-function.ts | 269 +++++++++++++++++++++++++++++++++------------- 1 file changed, 192 insertions(+), 77 deletions(-) diff --git a/typed-function.ts b/typed-function.ts index af4dc2d..4e14e62 100644 --- a/typed-function.ts +++ b/typed-function.ts @@ -21,10 +21,15 @@ function undef() { 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: () => void // TODO fix + implementation: (...args: any[]) => any // TODO figure out what this should be +} + +export type PrelimianarySignature = { + fn: number } export type Param = { @@ -41,7 +46,7 @@ export type Type = { typeIndex: number test: TestFunction isAny: boolean - conversion?: ConversionDef + conversion: ConversionDef | null conversionIndex: number } @@ -57,23 +62,63 @@ 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: any[] // TODO + isAny: boolean + index: number // TODO check if should be non null? + conversionsTo: ConversionDef[] // TODO } -export interface TypedFunction { - (...args: any[]): any // TODO fix - _typedFunctionData: any - signatures: Signature[] - createCount: number -} +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: any + _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 { @@ -81,16 +126,28 @@ export interface LegacyTypedFunction { signature: string; } -export interface TypedReference { +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: (self: Function) => Function // TODO figure out + callback: TypedReferenceToSelfCallback } +} +export interface TypedReferenceTo { referTo: { - callback: (self: Function) => Function // TODO figure out - references: any[] // TODO figure out + callback: TypedReferenceToCallback + references: string[] // TODO ensure this is correct } } +export type TypedReference = TypedReferenceToSelf | TypedReferenceTo + export type TypedReferenceMap = Record export type TestFunction = (x: any) => boolean @@ -102,6 +159,7 @@ export class TypedFunctionTypeError extends TypeError { actual?: string[] expected?: string[] expectedLength?: number + argument?: any } | null = null } @@ -110,6 +168,14 @@ export class TypedFunctionError extends Error { signature?: string actual?: string expected?: string + sourceFunction?: Function + } | null = {} +} + +export class TypedFunctionIndexError extends Error { + data: { + index?: number + argument?: TypedFunction | LegacyTypedFunction } | null = {} } @@ -131,6 +197,8 @@ function create() { return typeof x === "number" }, conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... }, { name: "string", @@ -138,6 +206,8 @@ function create() { return typeof x === "string" }, conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... }, { name: "boolean", @@ -145,6 +215,8 @@ function create() { return typeof x === "boolean" }, conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... }, { name: "Function", @@ -152,14 +224,24 @@ function create() { 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: "Array", test: Array.isArray, conversionsTo: [] }, { 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", @@ -167,14 +249,24 @@ function create() { 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: "Object", test: isPlainObject, conversionsTo: [] }, { 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", @@ -182,6 +274,8 @@ function create() { return x === undefined }, conversionsTo: [], + // isAny: ?? // TODO check what this should be + // index: ?? // TODO check what this should be... }, ] @@ -189,7 +283,9 @@ function create() { name: "any", test: ok, isAny: true, - conversionsTo: [], // TODO check if this is right!!! + // 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 @@ -198,14 +294,14 @@ function create() { // 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: any[] // Array of just type names, for the sake of ordering + 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 } + let typed: TypedFunction = { createCount: 0 } as any // TODO figure out a better way... /** * Takes a type name and returns the corresponding official type object @@ -240,7 +336,7 @@ function create() { * these types should be added before. The new types are added in the * order specified. */ - function addTypes(types: TypeDef[], beforeSpec: "any" | false = "any") { + function addTypes(types: TypeDef[], beforeSpec: "any" | "Object" | false = "any") { const beforeIndex = (beforeSpec ? findType(beforeSpec).index : typeList.length) || 0 // TODO check if right!!!!!!!! @@ -330,7 +426,7 @@ function create() { */ function isTypedFunction(entity: any): entity is TypedFunction { return ( - entity && isFunction(y) && "_typedFunctionData" in entity + entity && isFunction(entity) && "_typedFunctionData" in entity ) } @@ -376,8 +472,6 @@ function create() { * is found. */ - type FindSignatureOptions = { exact: boolean } - function findSignature( fn: TypedFunction, signature: string | string[], @@ -483,7 +577,7 @@ function create() { function find( fn: TypedFunction, signature: string | string[], - options: FindSignatureOptions + options?: FindSignatureOptions ) { return findSignature(fn, signature, options).implementation } @@ -530,7 +624,7 @@ function create() { let hasAny = false let paramName = restParam ? "..." : "" - const exactTypes = typeDefs.map(function (type) { + const exactTypes: Type[] = typeDefs.map(function (type) { hasAny = type.isAny || hasAny paramName += type.name + "|" @@ -551,6 +645,7 @@ function create() { hasAny: hasAny, hasConversion: false, restParam: restParam, + // typeSet: ?? // TODO check what this shoul dbe } } @@ -814,7 +909,7 @@ function create() { const nextMatchingDefs: Signature[] = [] matchingSignatures.forEach((signature) => { const param = getParamAtIndex(signature.params, index) - const test = compileTest(param) + const test = compileTest(param) // TODO check what should happen if null if ( (index < signature.params.length || hasRestParam(signature.params)) && test(args[index]) @@ -1141,8 +1236,8 @@ function create() { return matches } - interface CompileFn { - compileArgsPreprocessing(): any + interface PreprocessFn { + (...args: any[]): any } /** @@ -1181,7 +1276,7 @@ function create() { if (hasRestParam(params)) { const offset = params.length - 1 - fnPreprocess = function preprocessRestParams() { + fnPreprocess = function preprocessRestParams(this: PreprocessFn) { return fnConvert.apply( this, slice(arguments, 0, offset).concat([slice(arguments, offset)]) @@ -1275,10 +1370,10 @@ function create() { params: Param[], index: number, paramsSoFar: Param[] - ) { + ): Param[][] { // TODO check if Param[][] is correct if (index < params.length) { const param = params[index] - let resultingParams = [] + let resultingParams: Param[] = [] if (param.restParam) { // split the types of a rest parameter in two: @@ -1291,6 +1386,7 @@ function create() { hasAny: exactTypes.some((t) => t.isAny), hasConversion: false, restParam: true, + // typeSet: ?? // TODO check what this should be }) } resultingParams.push(param) @@ -1301,8 +1397,9 @@ function create() { types: [type], name: type.name, hasAny: type.isAny, - hasConversion: type.conversion, + hasConversion: !!type.conversion, // TODO check if this is correct restParam: false, + // typeSet: ?? // TODO check what this should be } }) } @@ -1363,10 +1460,10 @@ function create() { /** * Helper function for `resolveReferences` that returns a copy of - * functionList wihe any prior resolutions cleared out, in case we are + * functionList with any prior resolutions cleared out, in case we are * recycling signatures from a prior typed function construction. */ - function clearResolutions(functionList: TypedReference[]) { + function clearResolutions(functionList: TypedReference[]): TypedReference[] { return functionList.map((fn) => { if (isReferToSelf(fn)) { return referToSelf(fn.referToSelf.callback) @@ -1431,9 +1528,10 @@ function create() { const fn = resolvedFunctions[i] if (isReferToSelf(fn)) { - resolvedFunctions[i] = fn.referToSelf.callback(self) + const newResolvedFunction = fn.referToSelf.callback(self) + resolvedFunctions[i] = newResolvedFunction // Preserve reference in case signature is reused someday: - resolvedFunctions[i].referToSelf = fn.referToSelf + newResolvedFunction.referToSelf = fn.referToSelf nothingResolved = false } else if (isReferTo(fn)) { const resolvedReferences = collectResolutions( @@ -1442,12 +1540,13 @@ function create() { signatureMap ) if (resolvedReferences) { - resolvedFunctions[i] = fn.referTo.callback.apply( - this, + 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: - resolvedFunctions[i].referTo = fn.referTo + newResolvedFunction.referTo = fn.referTo nothingResolved = false } else { leftUnresolved = true @@ -1514,7 +1613,7 @@ function create() { const parsedParams = [] const originalFunctions = [] const signaturesMap = {} - const preliminarySignatures = [] // may have duplicates from conversions + const preliminarySignatures: (PrelimianarySignature | Signature)[] = [] // may have duplicates from conversions let signature for (signature in rawSignaturesMap) { // A) Protect against polluted Object prototype: @@ -1542,7 +1641,7 @@ function create() { originalFunctions.push(rawSignaturesMap[signature]) const conversionParams = params.map(expandParam) // E) Split the signatures and collect them up - let sp + let sp: Param[] for (sp of splitParams(conversionParams)) { const spName = stringifyParams(sp) preliminarySignatures.push({ @@ -1572,7 +1671,7 @@ function create() { signaturesMap[s] = resolvedFunctions[signaturesMap[s]] } } - const signatures = [] + 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 @@ -1673,7 +1772,7 @@ function create() { // create the typed function // fast, specialized version. Falls back to the slower, generic one if needed - function the_typed_fn(arg0, arg1) { + function the_typed_fn(arg0: any, arg1: any) { "use strict" if (arguments.length === len0 && test00(arg0) && test01(arg1)) { @@ -1729,7 +1828,7 @@ function create() { name: string, args: TArg[], signatures: Signature[] - ) { + ): never { throw createError(name, args, signatures) } @@ -1790,14 +1889,12 @@ function create() { * typed.referTo(signature1, signature2, ..., function callback(fn1, fn2, ...) { * // ... * }) - * - * @returns {{referTo: {references: string[], callback}}} */ - function referTo() { - let references = initial(arguments).map((s) => - stringifyParams(parseSignature(s)) + function referTo(...args: Signature[]) { + let references = initial(args).map((s) => + stringifyParams(parseSignature(s)) // TODO figure out what to do when null ) - const callback = last(arguments) + const callback = last(args) if (typeof callback !== "function") { throw new TypeError("Callback function expected as last argument") @@ -1806,7 +1903,7 @@ function create() { return makeReferTo(references, callback) } - function makeReferTo(references, callback) { + function makeReferTo(references: string[], callback: TypedReferenceCallback) { return { referTo: { references: references, callback: callback } } } @@ -1837,27 +1934,44 @@ function create() { * Test whether something is a referTo object, holding a list with reference * signatures and a callback. */ - function isReferTo(objectOrFn: TypedReference) { - return ( - objectOrFn && - isObject(objectOrFn.referTo) && - isArray(objectOrFn.referTo.references) && - isFunction(objectOrFn.referTo.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(objectOrFn: { - referToSelf: { callback: any } | Object - }) { - if (!objectOrFn) return false + function isReferToSelf(x: any): x is TypedReferenceToSelf { + function hasReferToSelfKey(x: any): x is { referToSelf: any } { + return 'referToSelf' in x + } - if (typeof objectOrFn.referToSelf === "object") return true + if (!x) return false + if (!hasReferToSelfKey(x)) return false + if (!isObject(x.referToSelf)) return false - return false + return true } /** @@ -1955,23 +2069,23 @@ function create() { * consistent with each other. If no name is specified, the name will be * an empty string. */ - typed = function (maybeName?: any): TypedFunction { + 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 < arguments.length; ++i) { - const item = arguments[i] - let theseSignatures = {} + for (let i = start; i < args.length; ++i) { + const item = args[i] + let theseSignatures: Record = {} let thisName - if (isFunction(m)) { + if (isFunction(item)) { thisName = item.name - if (typeof item.signature === "string") { + 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 + 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 @@ -1982,7 +2096,7 @@ function create() { } if (Object.keys(theseSignatures).length === 0) { - const err = new TypeError( + const err = new TypedFunctionIndexError( "Argument to 'typed' at index " + i + " is not a (typed) function, " + @@ -1993,7 +2107,7 @@ function create() { } if (!named) { - name = checkName(name, thisName) + name = checkName(name, thisName) // TODO check what to do when checkName returns null } mergeSignatures(allSignatures, theseSignatures) } @@ -2022,8 +2136,8 @@ function create() { * 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: Signature, beforeObjectTest = true) { - let before = "any" + typed.addType = function (type: TypeDef, beforeObjectTest = true) { + let before: "any" | "Object" = "any" if (beforeObjectTest !== false) { before = "Object" } @@ -2063,6 +2177,7 @@ function create() { return other.from !== conversion.from }) ) { + // TODO figure what to do with missing `to` key to.conversionsTo.push({ from: conversion.from, convert: conversion.convert,