diff --git a/.vscode/launch.json b/.vscode/launch.json index f02b0a1..1ed73d6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,6 +14,30 @@ "request": "launch", "skipFiles": ["/**"], "type": "pwa-node" + }, + { + "name": "Current TS Tests File", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "args": ["-r", "ts-node/register", "${relativeFile}"], + "cwd": "${workspaceRoot}", + "protocol": "inspector" + }, + { + "name": "mocha tests", + "type": "node", + "protocol": "inspector", + "request": "launch", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "stopOnEntry": false, + "args": [ + "--require", + "ts-node/register", + "${workspaceRoot}/test/**/toCoreFunctionMetadata.test.ts", + "--no-timeouts" + ], + "cwd": "${workspaceRoot}" } ] } diff --git a/package-lock.json b/package-lock.json index 2060284..b43b73c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@types/mocha": "^9.1.1", "@types/node": "^18.0.0", "@types/semver": "^7.3.9", + "@types/sinon": "^17.0.4", "@typescript-eslint/eslint-plugin": "^5.12.1", "@typescript-eslint/parser": "^5.12.1", "chai": "^4.2.0", @@ -39,14 +40,15 @@ "fs-extra": "^10.0.1", "globby": "^11.0.0", "minimist": "^1.2.6", - "mocha": "^9.1.1", + "mocha": "^11.1.0", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", "prettier": "^2.4.1", "semver": "^7.3.5", + "sinon": "^20.0.0", "ts-loader": "^9.3.1", "ts-node": "^3.3.0", - "typescript": "^4.5.5", + "typescript": "^4.9.5", "typescript4": "npm:typescript@~4.0.0", "webpack": "^5.74.0", "webpack-cli": "^4.10.0" @@ -240,6 +242,109 @@ "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -333,6 +438,59 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + } + }, + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@types/chai": { "version": "4.2.22", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", @@ -427,6 +585,23 @@ "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==", "dev": true }, + "node_modules/@types/sinon": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.4.tgz", + "integrity": "sha512-RHnIrhfPO3+tJT0s7cFaXGZvsL4bbR3/k7z3P312qMS4JaS2Tk+KiwiLx1S0rQ56ERj00u1/BtdyVd0FY+Pdew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", @@ -638,12 +813,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "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/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -933,10 +1102,11 @@ } }, "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==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1366,6 +1536,21 @@ "node": ">=6.0" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -1441,10 +1626,11 @@ } }, "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==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1464,12 +1650,13 @@ } }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1480,12 +1667,6 @@ } } }, - "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/deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -1577,6 +1758,13 @@ "node": ">=6.0.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.13", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", @@ -2594,6 +2782,23 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fork-ts-checker-webpack-plugin": { "version": "7.2.13", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.2.13.tgz", @@ -2727,6 +2932,7 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2877,15 +3083,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -3387,6 +3584,22 @@ "node": ">=0.10.0" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -3555,6 +3768,14 @@ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3651,12 +3872,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3702,6 +3924,16 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -3715,46 +3947,39 @@ } }, "node_modules/mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", - "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.3", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "4.2.1", - "ms": "2.1.3", - "nanoid": "3.3.1", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", + "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/mocha-junit-reporter": { @@ -3804,26 +4029,63 @@ "mocha": ">=3.1.2" } }, - "node_modules/mocha/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==", + "node_modules/mocha/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, + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "balanced-match": "^1.0.0" } }, "node_modules/mocha/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==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, + "node_modules/mocha/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mocha/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3834,12 +4096,13 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" @@ -3872,68 +4135,12 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mocha/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/mocha/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/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/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.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4114,6 +4321,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4186,6 +4400,30 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -4410,8 +4648,9 @@ "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=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4568,10 +4807,11 @@ } }, "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==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -4652,16 +4892,57 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sinon": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-20.0.0.tgz", + "integrity": "sha512-+FXOAbdnj94AQIxH0w1v8gzNxkawVvNqE3jUzRLptR71Oykeu2RrQXXl/VQjKay+Qnh73fDt/oDfMo6xMeDQbQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.5", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", @@ -4725,6 +5006,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "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, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -4782,6 +5079,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -4933,15 +5244,6 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/terser/node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -5218,10 +5520,11 @@ } }, "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5554,10 +5857,48 @@ } }, "node_modules/workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", - "dev": true + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" + }, + "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, + "license": "MIT", + "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/wrap-ansi-cjs": { + "name": "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, + "license": "MIT", + "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", @@ -5571,6 +5912,16 @@ "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", "dev": true }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -5580,13 +5931,33 @@ "node": ">= 6" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "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==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-unparser": { @@ -5798,6 +6169,71 @@ "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -5873,6 +6309,50 @@ "fastq": "^1.6.0" } }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1" + } + }, + "@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + }, + "dependencies": { + "type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true + } + } + }, "@types/chai": { "version": "4.2.22", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", @@ -5967,6 +6447,21 @@ "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==", "dev": true }, + "@types/sinon": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.4.tgz", + "integrity": "sha512-RHnIrhfPO3+tJT0s7cFaXGZvsL4bbR3/k7z3P312qMS4JaS2Tk+KiwiLx1S0rQ56ERj00u1/BtdyVd0FY+Pdew==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", @@ -6083,12 +6578,6 @@ } } }, - "@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 - }, "@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -6339,9 +6828,9 @@ "requires": {} }, "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==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, "ansi-regex": { @@ -6628,6 +7117,17 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -6691,9 +7191,9 @@ } }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -6708,20 +7208,12 @@ "dev": true }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "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 - } + "ms": "^2.1.3" } }, "deep-eql": { @@ -6791,6 +7283,12 @@ "esutils": "^2.0.2" } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "electron-to-chromium": { "version": "1.5.13", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", @@ -7550,6 +8048,16 @@ "is-callable": "^1.1.3" } }, + "foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + } + }, "fork-ts-checker-webpack-plugin": { "version": "7.2.13", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.2.13.tgz", @@ -7751,12 +8259,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -8101,6 +8603,16 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -8238,6 +8750,12 @@ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -8321,12 +8839,12 @@ "dev": true }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, @@ -8360,6 +8878,12 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -8370,54 +8894,73 @@ } }, "mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "4.2.1", - "ms": "2.1.3", - "nanoid": "3.3.1", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", + "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "dependencies": { + "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, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "balanced-match": "^1.0.0" } }, "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true }, + "glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "dependencies": { + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -8425,12 +8968,12 @@ "dev": true }, "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" } }, "strip-json-comments": { @@ -8447,38 +8990,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "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, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "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" - } } } }, @@ -8528,12 +9039,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8669,6 +9174,12 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8720,6 +9231,24 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -8869,7 +9398,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "require-from-string": { @@ -8969,9 +9498,9 @@ } }, "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -9035,6 +9564,33 @@ "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, + "sinon": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-20.0.0.tgz", + "integrity": "sha512-+FXOAbdnj94AQIxH0w1v8gzNxkawVvNqE3jUzRLptR71Oykeu2RrQXXl/VQjKay+Qnh73fDt/oDfMo6xMeDQbQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.5", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "supports-color": "^7.2.0" + }, + "dependencies": { + "diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -9092,6 +9648,17 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@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, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -9134,6 +9701,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -9244,17 +9820,6 @@ "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", "terser": "^5.26.0" - }, - "dependencies": { - "serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - } } }, "text-table": { @@ -9460,9 +10025,9 @@ } }, "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, "typescript4": { @@ -9679,11 +10244,33 @@ "dev": true }, "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, + "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, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -9696,16 +10283,37 @@ "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yargs-unparser": { diff --git a/package.json b/package.json index 10b16f3..9bfd3e3 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@types/mocha": "^9.1.1", "@types/node": "^18.0.0", "@types/semver": "^7.3.9", + "@types/sinon": "^17.0.4", "@typescript-eslint/eslint-plugin": "^5.12.1", "@typescript-eslint/parser": "^5.12.1", "chai": "^4.2.0", @@ -65,20 +66,21 @@ "eslint-plugin-header": "^3.1.1", "eslint-plugin-import": "^2.29.0", "eslint-plugin-prettier": "^4.0.0", - "eslint-webpack-plugin": "^3.2.0", "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-webpack-plugin": "^3.2.0", "fork-ts-checker-webpack-plugin": "^7.2.13", "fs-extra": "^10.0.1", "globby": "^11.0.0", "minimist": "^1.2.6", - "mocha": "^9.1.1", + "mocha": "^11.1.0", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", "prettier": "^2.4.1", "semver": "^7.3.5", + "sinon": "^20.0.0", "ts-loader": "^9.3.1", "ts-node": "^3.3.0", - "typescript": "^4.5.5", + "typescript": "^4.9.5", "typescript4": "npm:typescript@~4.0.0", "webpack": "^5.74.0", "webpack-cli": "^4.10.0" diff --git a/src/InvocationModel.ts b/src/InvocationModel.ts index d1958ae..c78900c 100644 --- a/src/InvocationModel.ts +++ b/src/InvocationModel.ts @@ -82,11 +82,9 @@ export class InvocationModel implements coreTypes.InvocationModel { } else { input = fromRpcTypedData(binding.data); } - if (isTimerTrigger(bindingType)) { input = toCamelCaseValue(input); } - if (isTrigger(bindingType)) { inputs.push(input); } else { diff --git a/src/converters/fromRpcTypedData.ts b/src/converters/fromRpcTypedData.ts index a8ed963..1fdb349 100644 --- a/src/converters/fromRpcTypedData.ts +++ b/src/converters/fromRpcTypedData.ts @@ -2,7 +2,10 @@ // Licensed under the MIT License. import { RpcTypedData } from '@azure/functions-core'; +import { StorageBlobClientOptions } from '../../types'; import { HttpRequest } from '../http/HttpRequest'; +import { isModelBindingData, parseConnectionDetails } from '../sdk-binding/connectionDetails'; +import { StorageBlobClientFactoryResolver } from '../storageBlobClientFactoryResolver'; import { isDefined } from '../utils/nonNull'; export function fromRpcTypedData(data: RpcTypedData | null | undefined): unknown { @@ -30,6 +33,20 @@ export function fromRpcTypedData(data: RpcTypedData | null | undefined): unknown return data.collectionDouble.double; } else if (data.collectionSint64 && isDefined(data.collectionSint64.sint64)) { return data.collectionSint64.sint64; + } else if (data.modelBindingData && isDefined(data.modelBindingData.content)) { + if (isModelBindingData(data.modelBindingData)) { + const blobConnectionDetails = parseConnectionDetails(data.modelBindingData.content); + + const storageBlobClientOptions: StorageBlobClientOptions = { + connection: blobConnectionDetails.Connection, + containerName: blobConnectionDetails.ContainerName, + blobName: blobConnectionDetails.BlobName, + }; + const storageBlobClientFactoryResolver = StorageBlobClientFactoryResolver.getInstance(); + return storageBlobClientFactoryResolver.createClient(storageBlobClientOptions); + } + //TODO determine if we need to throw error. + return data.modelBindingData; } else { return undefined; } diff --git a/src/converters/toCoreFunctionMetadata.ts b/src/converters/toCoreFunctionMetadata.ts index 390c9ea..903833a 100644 --- a/src/converters/toCoreFunctionMetadata.ts +++ b/src/converters/toCoreFunctionMetadata.ts @@ -11,12 +11,13 @@ import { toRpcDuration } from './toRpcDuration'; export function toCoreFunctionMetadata(name: string, options: GenericFunctionOptions): coreTypes.FunctionMetadata { const bindings: Record = {}; const bindingNames: string[] = []; - const trigger = options.trigger; + bindings[trigger.name] = { ...trigger, direction: 'in', type: isTrigger(trigger.type) ? trigger.type : trigger.type + 'Trigger', + properties: addSdkBindingsFlag(options.trigger?.sdkBinding), }; bindingNames.push(trigger.name); @@ -25,6 +26,7 @@ export function toCoreFunctionMetadata(name: string, options: GenericFunctionOpt bindings[input.name] = { ...input, direction: 'in', + properties: addSdkBindingsFlag(input?.sdkBinding), }; bindingNames.push(input.name); } @@ -74,3 +76,12 @@ export function toCoreFunctionMetadata(name: string, options: GenericFunctionOpt return { name, bindings, retryOptions }; } + +function addSdkBindingsFlag(sdkBindingType?: boolean | unknown): { [key: string]: string } { + //Ensure that trigger type that is passed is valid and supported. + if (sdkBindingType !== undefined && sdkBindingType === true) { + return { supportsDeferredBinding: 'true' }; + } + + return { supportsDeferredBinding: 'false' }; +} diff --git a/src/index.ts b/src/index.ts index d3e2911..7e525b9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ export { HttpResponse } from './http/HttpResponse'; export * as input from './input'; export { InvocationContext } from './InvocationContext'; export * as output from './output'; +export * from './storageBlobClientFactoryResolver'; export * as trigger from './trigger'; export { Disposable } from './utils/Disposable'; diff --git a/src/sdk-binding/connectionDetails.ts b/src/sdk-binding/connectionDetails.ts new file mode 100644 index 0000000..0183cbc --- /dev/null +++ b/src/sdk-binding/connectionDetails.ts @@ -0,0 +1,90 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { ModelBindingData } from '@azure/functions-core'; + +export type BlobConnectionDetails = { + Connection: string; + ContainerName: string; + BlobName: string; +}; + +// Define the `ServiceBusConnectionInfo` type that extends `ConnectionInfo` +//TODO Define other connectionInfo example ServiceBusConnectionDetails + +/** + * Type Guard to check if an object is of type BlobConnectionInfo + */ +// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access +function isBlobConnectionDetails(obj: unknown): obj is BlobConnectionDetails { + return ( + obj !== null && + typeof obj === 'object' && + 'Connection' in obj && + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + typeof (obj as any).Connection === 'string' && + 'ContainerName' in obj && + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + typeof (obj as any).ContainerName === 'string' && + 'BlobName' in obj && + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + typeof (obj as any).BlobName === 'string' + ); +} + +/** + * Function to parse JSON and determine its type + * @param jsonBuffer Bufer that holds the JSON string to parse + * @returns Either `BlobConnectionDetails` or `ServiceBusConnectionDetails` + */ +export function parseConnectionDetails(jsonBuffer: Buffer | null | undefined): BlobConnectionDetails { + if (jsonBuffer === null || jsonBuffer === undefined) { + throw new Error('Connection details content is null or undefined'); + } + const parsedObject: unknown = JSON.parse(jsonBuffer.toString()); + + if (isBlobConnectionDetails(parsedObject)) { + return parsedObject; + } + //TODO add other parser for different resource types + else { + throw new Error('Invalid connection info type'); + } +} + +/** + * Type guard to check if an object conforms to the ModelBindingData interface + * @param obj Object to check + * @returns True if object is ModelBindingData + */ +export function isModelBindingData(obj: unknown): obj is ModelBindingData { + if (!obj || typeof obj !== 'object') { + return false; + } + + const candidate = obj as Record; + + // Check content property if it exists + if ( + !('content' in candidate) || + candidate.content === null || + candidate.content === undefined || + !(candidate.content instanceof Buffer) + ) { + return false; + } + + // Check string properties if they exist + const stringProps = ['contentType', 'source', 'version']; + for (const prop of stringProps) { + if ( + prop in candidate && + candidate[prop] !== null && + candidate[prop] !== undefined && + typeof candidate[prop] !== 'string' + ) { + return false; + } + } + return true; +} diff --git a/src/storageBlobClientFactoryResolver.ts b/src/storageBlobClientFactoryResolver.ts new file mode 100644 index 0000000..5a9802f --- /dev/null +++ b/src/storageBlobClientFactoryResolver.ts @@ -0,0 +1,89 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { StorageBlobClientFactory, StorageBlobClientOptions } from '../types'; + +/** + * Registry for Storage Blob Client factory implementations. + * Manages the registration and retrieval of blob client factories across the application. + * + * @example + * ```typescript + * // Register a factory + * StorageBlobClientRegistry.getInstance().registerFactory((options) => { + * return new MyCustomBlobClient(options.connection, options.path); + * }); + * + * // Create a blob client + * const blobClient = StorageBlobClientRegistry.getInstance().createClient({ + * connection: "MyStorageConnection", + * path: "container/blob.txt" + * }); + * ``` + */ +export class StorageBlobClientFactoryResolver { + private static instance: StorageBlobClientFactoryResolver; + private factory: StorageBlobClientFactory | undefined; + + /** + * Private constructor to enforce singleton pattern + */ + private constructor() { + // Initialize as needed + } + + /** + * Gets the singleton instance of the registry + * @returns The singleton instance + */ + static getInstance(): StorageBlobClientFactoryResolver { + if (!StorageBlobClientFactoryResolver.instance) { + StorageBlobClientFactoryResolver.instance = new StorageBlobClientFactoryResolver(); + } + return StorageBlobClientFactoryResolver.instance; + } + + /** + * Registers a factory implementation to create Storage Blob Clients + * @param factory - The factory function implementation + * @throws Error if a factory is already registered + */ + registerFactory(factory: StorageBlobClientFactory): void { + if (this.factory) { + throw new Error( + 'A StorageBlobClient factory is already registered. Unregister the existing factory first.' + ); + } + this.factory = factory; + } + + /** + * Unregisters the current factory implementation + */ + unregisterFactory(): void { + this.factory = undefined; + } + + /** + * Creates a Storage Blob Client using the registered factory + * @param options - Options for creating the Storage Blob Client + * @returns The created Storage Blob Client + * @throws Error if no factory is registered + */ + createClient(options: StorageBlobClientOptions): unknown { + if (!this.factory) { + throw new Error( + 'StorageBlobClient factory is not registered. Register a factory implementation before creating clients.' + ); + } + return this.factory(options); + } + + /** + * Checks if a factory is registered + * @returns true if a factory is registered, false otherwise + */ + hasFactory(): boolean { + return this.factory !== undefined; + } +} diff --git a/src/trigger.ts b/src/trigger.ts index f709abb..ed2f7f6 100644 --- a/src/trigger.ts +++ b/src/trigger.ts @@ -13,7 +13,7 @@ import { HttpTrigger, HttpTriggerOptions, MySqlTrigger, - MySqlTriggerOptions, + MySqlTriggerOptions, ServiceBusQueueTrigger, ServiceBusQueueTriggerOptions, ServiceBusTopicTrigger, diff --git a/test/converters/fromRpcTypedData.test.ts b/test/converters/fromRpcTypedData.test.ts index 1ffbbcc..41fb386 100644 --- a/test/converters/fromRpcTypedData.test.ts +++ b/test/converters/fromRpcTypedData.test.ts @@ -7,6 +7,10 @@ import { fromString } from 'long'; import { HttpRequest } from '../../src'; import { fromRpcTypedData } from '../../src/converters/fromRpcTypedData'; import Long = require('long'); +import { ModelBindingData, RpcTypedData } from '@azure/functions-core'; +import sinon = require('sinon'); +import * as connectionDetailsModule from '../../src/sdk-binding/connectionDetails'; +import * as storageBlobClientFactoryResolverModule from '../../src/storageBlobClientFactoryResolver'; describe('fromRpcTypedData', () => { it('null', () => { @@ -110,3 +114,211 @@ describe('fromRpcTypedData', () => { expect(result[1].toString()).to.equal('9007199254740992'); }); }); + +describe('fromRpcTypedData - modelBindingData path', () => { + let sandbox: sinon.SinonSandbox; + let isModelBindingDataStub: sinon.SinonStub; + let parseConnectionDetailsStub: sinon.SinonStub; + let createClientStub: sinon.SinonStub; + let mockFactoryResolver: any; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + + // Mock isModelBindingData + isModelBindingDataStub = sandbox.stub(connectionDetailsModule, 'isModelBindingData'); + + // Mock parseConnectionDetails + parseConnectionDetailsStub = sandbox.stub(connectionDetailsModule, 'parseConnectionDetails'); + + // Create a mock resolver with a stub createClient method + mockFactoryResolver = { + createClient: sandbox.stub(), + }; + + // Mock the getInstance method to return our mock resolver + sandbox + .stub(storageBlobClientFactoryResolverModule.StorageBlobClientFactoryResolver, 'getInstance') + .returns(mockFactoryResolver); + + // Store reference to createClient stub for ease of use + createClientStub = mockFactoryResolver.createClient; + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should create a blob client when provided with valid model binding data', () => { + // Arrange + const modelBindingData: ModelBindingData = { + content: Buffer.from( + JSON.stringify({ + Connection: 'test-connection', + ContainerName: 'test-container', + BlobName: 'test-blob.txt', + }) + ), + contentType: 'application/json', + }; + + const rpcTypedData: RpcTypedData = { modelBindingData }; + + isModelBindingDataStub.returns(true); + parseConnectionDetailsStub.returns({ + Connection: 'test-connection', + ContainerName: 'test-container', + BlobName: 'test-blob.txt', + }); + + const mockBlobClient = { + name: 'mockBlobClient', + download: () => {}, + }; + createClientStub.returns(mockBlobClient); + + // Act + const result = fromRpcTypedData(rpcTypedData); + + // Assert + expect(isModelBindingDataStub.calledOnce).to.be.true; + expect(isModelBindingDataStub.calledWith(modelBindingData)).to.be.true; + + expect(parseConnectionDetailsStub.calledOnce).to.be.true; + expect(parseConnectionDetailsStub.calledWith(modelBindingData.content)).to.be.true; + + expect(createClientStub.calledOnce).to.be.true; + expect(createClientStub.firstCall.args[0]).to.deep.equal({ + connection: 'test-connection', + containerName: 'test-container', + blobName: 'test-blob.txt', + }); + + expect(result).to.equal(mockBlobClient); + }); + + it('should handle when isModelBindingData returns false', () => { + // Arrange + const modelBindingData: ModelBindingData = { + content: Buffer.from('invalid-content'), + contentType: 'text/plain', + }; + + const rpcTypedData: RpcTypedData = { modelBindingData }; + + isModelBindingDataStub.returns(false); + + // Act + const result = fromRpcTypedData(rpcTypedData); + + // Assert + expect(isModelBindingDataStub.calledOnce).to.be.true; + expect(parseConnectionDetailsStub.called).to.be.false; + expect(createClientStub.called).to.be.false; + + // Should return the modelBindingData as-is + expect(result).to.equal(modelBindingData); + }); + + it('should propagate errors from parseConnectionDetails', () => { + // Arrange + const modelBindingData: ModelBindingData = { + content: Buffer.from('invalid-json'), + contentType: 'application/json', + }; + + const rpcTypedData: RpcTypedData = { modelBindingData }; + + isModelBindingDataStub.returns(true); + parseConnectionDetailsStub.throws(new Error('Invalid JSON format')); + + // Act & Assert + expect(() => fromRpcTypedData(rpcTypedData)).to.throw('Invalid JSON format'); + expect(createClientStub.called).to.be.false; + }); + + it('should propagate errors from createClient', () => { + // Arrange + const modelBindingData: ModelBindingData = { + content: Buffer.from( + JSON.stringify({ + Connection: 'test-connection', + ContainerName: 'test-container', + BlobName: 'test-blob.txt', + }) + ), + contentType: 'application/json', + }; + + const rpcTypedData: RpcTypedData = { modelBindingData }; + + isModelBindingDataStub.returns(true); + parseConnectionDetailsStub.returns({ + Connection: 'test-connection', + ContainerName: 'test-container', + BlobName: 'test-blob.txt', + }); + + createClientStub.throws(new Error('Factory not registered')); + + // Act & Assert + expect(() => fromRpcTypedData(rpcTypedData)).to.throw('Factory not registered'); + }); + + it('should handle undefined modelBindingData content', () => { + // Arrange + const modelBindingData: ModelBindingData = { + // Missing content + contentType: 'application/json', + }; + + const rpcTypedData: RpcTypedData = { modelBindingData }; + + // Act + const result = fromRpcTypedData(rpcTypedData); + + // Assert + expect(isModelBindingDataStub.called).to.be.false; + expect(parseConnectionDetailsStub.called).to.be.false; + expect(createClientStub.called).to.be.false; + + expect(result).to.be.undefined; + }); + + it('should handle special characters in blob names', () => { + // Arrange + const blobName = 'special/char+blob#name.txt'; + const modelBindingData: ModelBindingData = { + content: Buffer.from( + JSON.stringify({ + Connection: 'test-connection', + ContainerName: 'test-container', + BlobName: blobName, + }) + ), + contentType: 'application/json', + }; + + const rpcTypedData: RpcTypedData = { modelBindingData }; + + isModelBindingDataStub.returns(true); + parseConnectionDetailsStub.returns({ + Connection: 'test-connection', + ContainerName: 'test-container', + BlobName: blobName, + }); + + const mockBlobClient = { + name: blobName, + download: () => {}, + }; + createClientStub.returns(mockBlobClient); + + // Act + const result = fromRpcTypedData(rpcTypedData); + + // Assert + expect(createClientStub.firstCall.args[0].blobName).to.equal(blobName); + expect(result).to.equal(mockBlobClient); + }); +}); diff --git a/test/converters/toCoreFunctionMetadata.test.ts b/test/converters/toCoreFunctionMetadata.test.ts index 764da9d..59731ae 100644 --- a/test/converters/toCoreFunctionMetadata.test.ts +++ b/test/converters/toCoreFunctionMetadata.test.ts @@ -5,15 +5,20 @@ import 'mocha'; import { expect } from 'chai'; import { output, trigger } from '../../src'; import { toCoreFunctionMetadata } from '../../src/converters/toCoreFunctionMetadata'; +import { InvocationContext } from '../../types'; describe('toCoreFunctionMetadata', () => { - const handler = () => {}; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const handler = (blob: Buffer, context: InvocationContext) => {}; const expectedHttpTrigger = { authLevel: 'anonymous', methods: ['GET', 'POST'], type: 'httpTrigger', name: 'httpTrigger433d175fc9', direction: 'in', + properties: { + supportsDeferredBinding: 'false', + }, }; const expectedHttpOutput = { type: 'http', name: 'httpOutput9a706511b1', direction: 'out' }; const expectedQueueOutput1 = { @@ -155,3 +160,177 @@ describe('toCoreFunctionMetadata', () => { }); }); }); + +describe('toCoreFunctionMetadata sdk binding tests', () => { + const handler = () => {}; // Mock handler function + + it('should set supportsDeferredBinding to true for blob trigger when sdkBinding is true', () => { + const result = toCoreFunctionMetadata('blobFunction', { + handler, + trigger: { + ...trigger.storageBlob({ + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + sdkBinding: true, + }), + }, + return: output.http({}), + }); + + expect(result).to.deep.include({ + name: 'blobFunction', + bindings: { + blobTrigger97e7289e53: { + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + sdkBinding: true, + type: 'blobTrigger', + name: 'blobTrigger97e7289e53', + direction: 'in', + properties: { + supportsDeferredBinding: 'true', + }, + }, + $return: { type: 'http', name: 'httpOutput9a706511b1', direction: 'out' }, + }, + retryOptions: undefined, + }); + }); + + it('should set supportsDeferredBinding to false for blob trigger when sdkBinding is false', () => { + const result = toCoreFunctionMetadata('blobFunction', { + handler, + trigger: { + ...trigger.storageBlob({ + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + sdkBinding: false, + }), + }, + return: output.http({}), + }); + + expect(result).to.deep.include({ + name: 'blobFunction', + bindings: { + blobTrigger81b6e1578f: { + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + sdkBinding: false, + type: 'blobTrigger', + name: 'blobTrigger81b6e1578f', + direction: 'in', + properties: { + supportsDeferredBinding: 'false', + }, + }, + $return: { type: 'http', name: 'httpOutput9a706511b1', direction: 'out' }, + }, + retryOptions: undefined, + }); + }); + + it('should set supportsDeferredBinding to false for blob trigger when sdkBinding is undefined', () => { + const result = toCoreFunctionMetadata('blobFunction', { + handler, + trigger: trigger.storageBlob({ + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + }), + return: output.http({}), + }); + + expect(result).to.deep.equal({ + name: 'blobFunction', + bindings: { + blobTrigger44ba8238b9: { + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + type: 'blobTrigger', + name: 'blobTrigger44ba8238b9', + direction: 'in', + properties: { + supportsDeferredBinding: 'false', + }, + }, + $return: { type: 'http', name: 'httpOutput9a706511b1', direction: 'out' }, + }, + retryOptions: undefined, + }); + }); + + it('should handle sdk binding for extra inputs', () => { + const result = toCoreFunctionMetadata('funcName', { + handler, + trigger: trigger.http({}), + extraInputs: [ + { + ...trigger.storageBlob({ + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + sdkBinding: true, + }), + }, + ], + }); + + expect(result).to.deep.equal({ + name: 'funcName', + bindings: { + httpTrigger433d175fc9: { + authLevel: 'anonymous', + methods: ['GET', 'POST'], + type: 'httpTrigger', + name: 'httpTrigger433d175fc9', + direction: 'in', + properties: { supportsDeferredBinding: 'false' }, + }, + blobTrigger97e7289e53: { + path: 'samples-workitems/{name}', + connection: 'AzureWebJobsStorage', + sdkBinding: true, + type: 'blobTrigger', + name: 'blobTrigger97e7289e53', + direction: 'in', + properties: { supportsDeferredBinding: 'true' }, + }, + }, + retryOptions: undefined, + }); + }); +}); + +describe('toCoreFunctionMetadata error handling', () => { + const handler = () => {}; + + it('should throw error for duplicate binding names', () => { + expect(() => { + toCoreFunctionMetadata('funcName', { + handler, + trigger: trigger.http({}), + extraInputs: [ + { + type: 'httpTrigger', // This creates a duplicate with the trigger + name: 'httpTrigger433d175fc9', // Using same name that would be generated by trigger.http({}) + }, + ], + }); + }).to.throw(/duplicate bindings found/i); + }); + + it('should preserve trigger type for non-trigger inputs', () => { + const result = toCoreFunctionMetadata('funcName', { + handler, + trigger: trigger.http({}), + extraInputs: [ + { + type: 'blob', + name: 'blobInput', + path: 'path/to/blob', + }, + ], + }); + + expect(result.bindings['blobInput']?.type).to.equal('blob'); + }); +}); diff --git a/test/deferred-binding/connectionDetails.test.ts b/test/deferred-binding/connectionDetails.test.ts new file mode 100644 index 0000000..ee961b6 --- /dev/null +++ b/test/deferred-binding/connectionDetails.test.ts @@ -0,0 +1,138 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { expect } from 'chai'; +import { isModelBindingData, parseConnectionDetails } from '../../src/sdk-binding/connectionDetails'; + +describe('connectionDetails', () => { + describe('parseConnectionDetails', () => { + it('should parse valid BlobConnectionDetails JSON', () => { + const validJson = JSON.stringify({ + Connection: + 'DefaultEndpointsProtocol=https;AccountName=storageaccount;AccountKey=key==;EndpointSuffix=core.windows.net', + ContainerName: 'mycontainer', + BlobName: 'myblob.txt', + }); + + const buffer = Buffer.from(validJson); + const result = parseConnectionDetails(buffer); + + expect(result).to.deep.equal({ + Connection: + 'DefaultEndpointsProtocol=https;AccountName=storageaccount;AccountKey=key==;EndpointSuffix=core.windows.net', + ContainerName: 'mycontainer', + BlobName: 'myblob.txt', + }); + }); + + it('should throw error for null buffer', () => { + expect(() => parseConnectionDetails(null)).to.throw('Connection details content is null or undefined'); + }); + + it('should throw error for undefined buffer', () => { + expect(() => parseConnectionDetails(undefined)).to.throw('Connection details content is null or undefined'); + }); + + it('should throw error for invalid JSON', () => { + const invalidJson = Buffer.from('{not valid json}'); + expect(() => parseConnectionDetails(invalidJson)).to.throw(SyntaxError); + }); + + it('should throw error for JSON that is not BlobConnectionDetails', () => { + const invalidConnectionDetails = JSON.stringify({ + NotConnection: 'something', + NotContainerName: 'something else', + }); + + const buffer = Buffer.from(invalidConnectionDetails); + expect(() => parseConnectionDetails(buffer)).to.throw('Invalid connection info type'); + }); + + it('should throw error for incomplete BlobConnectionDetails', () => { + const incompleteJson = JSON.stringify({ + Connection: 'connection-string', + // Missing ContainerName and BlobName + }); + + const buffer = Buffer.from(incompleteJson); + expect(() => parseConnectionDetails(buffer)).to.throw('Invalid connection info type'); + }); + + it('should throw error when properties have wrong types', () => { + const wrongTypesJson = JSON.stringify({ + Connection: 'string-ok', + ContainerName: 123, // Not a string + BlobName: true, // Not a string + }); + + const buffer = Buffer.from(wrongTypesJson); + expect(() => parseConnectionDetails(buffer)).to.throw('Invalid connection info type'); + }); + }); + + describe('isModelBindingData', () => { + // Note: There appears to be a bug in the implementation of isModelBindingData + // It returns false when content IS a Buffer, which is opposite of what we'd expect + + it('should identify null as not ModelBindingData', () => { + expect(isModelBindingData(null)).to.be.false; + }); + + it('should identify non-object as not ModelBindingData', () => { + expect(isModelBindingData('string')).to.be.false; + expect(isModelBindingData(123)).to.be.false; + expect(isModelBindingData(true)).to.be.false; + }); + + it('should handle objects with string properties correctly', () => { + const validStringProps = { + content: Buffer.from('test'), + contentType: 'application/json', + source: 'test-source', + version: '1.0', + }; + + // This should pass as all string properties are valid + expect(isModelBindingData(validStringProps)).to.be.true; + + // Test with invalid string property types + const invalidStringProps = { + contentType: 123, // Not a string + source: 'test-source', + version: '1.0', + }; + + expect(isModelBindingData(invalidStringProps)).to.be.false; + }); + + //The current implementation returns false when content IS a Buffer + it('returns false when content IS a Buffer', () => { + const modelBindingWithBuffer = { + content: Buffer.from('test'), + contentType: 'text/plain', + }; + expect(isModelBindingData(modelBindingWithBuffer)).to.be.true; + }); + + it('should handle empty objects', () => { + expect(isModelBindingData({})).to.be.false; // This is potentially incorrect behavior + }); + }); + + // This provides an additional test suite for isBlobConnectionDetails through parseConnectionDetails + describe('isBlobConnectionDetails (indirect tests)', () => { + it('should identify valid BlobConnectionDetails object', () => { + const validObject = { + Connection: 'connection-string', + ContainerName: 'container', + BlobName: 'blob', + }; + + // We can't test isBlobConnectionDetails directly as it's private + // But we can test it through parseConnectionDetails + const buffer = Buffer.from(JSON.stringify(validObject)); + const result = parseConnectionDetails(buffer); + expect(result).to.deep.equal(validObject); + }); + }); +}); diff --git a/test/storageBlobClientFactoryResolver.test.ts b/test/storageBlobClientFactoryResolver.test.ts new file mode 100644 index 0000000..a170bbc --- /dev/null +++ b/test/storageBlobClientFactoryResolver.test.ts @@ -0,0 +1,195 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { expect } from 'chai'; +import { StorageBlobClientFactoryResolver } from '../src/storageBlobClientFactoryResolver'; +import { Disposable } from '../src/utils/Disposable'; +import { StorageBlobClientOptions } from '../types'; + +describe('StorageBlobClientFactoryResolver', () => { + // Store reference to original instance for cleanup + let originalInstance: StorageBlobClientFactoryResolver | undefined; + + before(() => { + // Save original instance if it exists (for restoration after tests) + originalInstance = (StorageBlobClientFactoryResolver as any).instance; + }); + + afterEach(() => { + // Reset the singleton instance between tests to ensure test isolation + (StorageBlobClientFactoryResolver as any).instance = undefined; + + // Make sure any factory is unregistered + try { + StorageBlobClientFactoryResolver.getInstance().unregisterFactory(); + } catch (error) { + // Ignore errors during cleanup + } + }); + + after(() => { + // Restore original instance if there was one + if (originalInstance) { + (StorageBlobClientFactoryResolver as any).instance = originalInstance; + } + }); + + describe('getInstance', () => { + it('should return the same instance when called multiple times', () => { + // Arrange & Act + const instance1 = StorageBlobClientFactoryResolver.getInstance(); + const instance2 = StorageBlobClientFactoryResolver.getInstance(); + + // Assert + expect(instance1).to.equal(instance2); + }); + + it('should create a new instance when one does not exist', () => { + // Arrange + (StorageBlobClientFactoryResolver as any).instance = undefined; + + // Act + const instance = StorageBlobClientFactoryResolver.getInstance(); + + // Assert + expect(instance).to.be.instanceOf(StorageBlobClientFactoryResolver); + }); + }); + + describe('registerFactory', () => { + it('should register a factory successfully', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + const mockFactory = () => ({ mockClient: true }); + + // Act + resolver.registerFactory(mockFactory); + + // Assert + expect(resolver.hasFactory()).to.be.true; + }); + + it('should throw when attempting to register a factory when one is already registered', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + const mockFactory1 = () => ({ mockClient1: true }); + const mockFactory2 = () => ({ mockClient2: true }); + + // Act & Assert + resolver.registerFactory(mockFactory1); + expect(() => resolver.registerFactory(mockFactory2)).to.throw( + 'A StorageBlobClient factory is already registered. Unregister the existing factory first.' + ); + }); + }); + + describe('unregisterFactory', () => { + it('should unregister a factory successfully', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + const mockFactory = () => ({ mockClient: true }); + resolver.registerFactory(mockFactory); + + // Act + resolver.unregisterFactory(); + + // Assert + expect(resolver.hasFactory()).to.be.false; + }); + + it('should do nothing when unregistering and no factory is registered', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + + // Act & Assert (should not throw) + resolver.unregisterFactory(); + expect(resolver.hasFactory()).to.be.false; + }); + }); + + describe('createClient', () => { + it('should create a client using the registered factory', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + const mockClientResult = { blobClient: { name: 'test-blob' }, containerClient: { name: 'test-container' } }; + let capturedOptions: StorageBlobClientOptions | undefined; + + const mockFactory = (options: StorageBlobClientOptions) => { + capturedOptions = options; + return mockClientResult; + }; + + resolver.registerFactory(mockFactory); + + const options: StorageBlobClientOptions = { + connection: 'test-connection', + containerName: 'test-container', + blobName: 'test-blob.txt', + }; + + // Act + const result = resolver.createClient(options); + + // Assert + expect(result).to.equal(mockClientResult); + expect(capturedOptions).to.equal(options); + }); + + it('should throw when creating client with no factory registered', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + const options: StorageBlobClientOptions = { + connection: 'test-connection', + containerName: 'test-container', + blobName: 'test-blob.txt', + }; + + // Act & Assert + expect(() => resolver.createClient(options)).to.throw( + 'StorageBlobClient factory is not registered. Register a factory implementation before creating clients.' + ); + }); + }); + + describe('hasFactory', () => { + it('should return true when factory is registered', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + const mockFactory = () => ({ mockClient: true }); + + // Act + resolver.registerFactory(mockFactory); + + // Assert + expect(resolver.hasFactory()).to.be.true; + }); + + it('should return false when no factory is registered', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + + // Act & Assert + expect(resolver.hasFactory()).to.be.false; + }); + }); + + describe('Integration with Disposable pattern', () => { + it('should support the Disposable pattern for cleanup', () => { + // Arrange + const resolver = StorageBlobClientFactoryResolver.getInstance(); + const mockFactory = () => ({ mockClient: true }); + resolver.registerFactory(mockFactory); + + // Act + const disposable = Disposable.from({ + dispose: () => resolver.unregisterFactory(), + }); + + expect(resolver.hasFactory()).to.be.true; + disposable.dispose(); + + // Assert + expect(resolver.hasFactory()).to.be.false; + }); + }); +}); diff --git a/types-core/index.d.ts b/types-core/index.d.ts index 2fb3506..9e2e448 100644 --- a/types-core/index.d.ts +++ b/types-core/index.d.ts @@ -391,12 +391,18 @@ declare module '@azure/functions-core' { direction?: RpcBindingDirection | null; dataType?: RpcBindingDataType | null; + + properties?: RpcBindingProperties | null; } type RpcBindingDirection = 'in' | 'out' | 'inout'; type RpcBindingDataType = 'undefined' | 'string' | 'binary' | 'stream'; + interface RpcBindingProperties { + supportsDeferredBinding?: 'true' | 'false' | null; + } + interface RpcRetryOptions { maxRetryCount?: number | null; @@ -433,6 +439,15 @@ declare module '@azure/functions-core' { collectionDouble?: RpcCollectionDouble | null; collectionSint64?: RpcCollectionSInt64 | null; + + modelBindingData?: ModelBindingData | null; + } + + interface ModelBindingData { + content?: Buffer | null; + contentType?: string | null; + source?: string | null; + version?: string | null; } interface RpcCollectionSInt64 { diff --git a/types/InvocationContext.d.ts b/types/InvocationContext.d.ts index 8815bdf..c991557 100644 --- a/types/InvocationContext.d.ts +++ b/types/InvocationContext.d.ts @@ -129,7 +129,7 @@ export interface InvocationContextExtraInputs { * @input the configuration object for this SQL input */ get(input: SqlInput): unknown; - + /** * Get a secondary MySql items input for this invocation * @input the configuration object for this MySql input @@ -223,7 +223,7 @@ export interface InvocationContextExtraOutputs { * @message the output event(s) value */ set(output: EventGridOutput, events: EventGridPartialEvent | EventGridPartialEvent[]): void; - + /** * Set a secondary MySql items output for this invocation * @output the configuration object for this MySql output diff --git a/types/index.d.ts b/types/index.d.ts index 2676a89..af999d7 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -23,6 +23,7 @@ export * from './serviceBus'; export * from './setup'; export * from './sql'; export * from './storage'; +export * from './storageBlobClientFactoryResolver'; export * from './table'; export * from './timer'; export * as trigger from './trigger'; diff --git a/types/input.d.ts b/types/input.d.ts index 52d8c68..b264405 100644 --- a/types/input.d.ts +++ b/types/input.d.ts @@ -4,10 +4,10 @@ import { CosmosDBInput, CosmosDBInputOptions } from './cosmosDB'; import { GenericInputOptions } from './generic'; import { FunctionInput } from './index'; +import { MySqlInput, MySqlInputOptions } from './mySql'; import { SqlInput, SqlInputOptions } from './sql'; import { StorageBlobInput, StorageBlobInputOptions } from './storage'; import { TableInput, TableInputOptions } from './table'; -import { MySqlInput, MySqlInputOptions } from './mySql'; import { WebPubSubConnectionInput, WebPubSubConnectionInputOptions, diff --git a/types/storage.d.ts b/types/storage.d.ts index 2ed33ba..491fcb4 100644 --- a/types/storage.d.ts +++ b/types/storage.d.ts @@ -29,6 +29,11 @@ export interface StorageBlobOptions { * An app setting (or environment variable) with the storage connection string to be used by this blob input or output */ connection: string; + + /** + * Whether to use sdk binding for this blob operation. + * */ + sdkBinding?: boolean; } export interface StorageQueueOptions { @@ -64,3 +69,20 @@ export type StorageQueueTrigger = FunctionTrigger & StorageQueueTriggerOptions; export type StorageQueueOutputOptions = StorageQueueOptions; export type StorageQueueOutput = FunctionOutput & StorageQueueOutputOptions; + +export interface StorageBlobClientOptions { + connection: string; + containerName: string; + blobName: string; +} +type StorageBlobClientFactory = (storageBlobClientOptions: StorageBlobClientOptions) => unknown; + +// Class to manage the registration and creation of Storage Blob Clients Factory +export class StorageBlobClientFactoryResolver { + private constructor(); + static getInstance(): StorageBlobClientFactoryResolver; + registerFactory(factory: StorageBlobClientFactory): void; + unregisterFactory(): void; + createClient(options: StorageBlobClientOptions): unknown; + hasFactory(): boolean; +} diff --git a/types/storageBlobClientFactoryResolver.d.ts b/types/storageBlobClientFactoryResolver.d.ts new file mode 100644 index 0000000..ee613ef --- /dev/null +++ b/types/storageBlobClientFactoryResolver.d.ts @@ -0,0 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { StorageBlobClientFactoryResolver } from './storage'; + +export function registerStorageBlobClientFactory(f: StorageBlobClientFactoryResolver): void;