diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 3ac9aeb..78d7d75 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,5 @@ { // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format - "recommendations": [ - "dbaeumer.vscode-eslint" - ] + "recommendations": ["esbenp.prettier-vscode"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 30bf8c2..50fe347 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,6 @@ "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" + "typescript.tsc.autoDetect": "off", + "nuxt.isNuxtApp": false } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index dc32da7..41d9b31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,13 +14,16 @@ "@types/glob": "^7.2.0", "@types/mocha": "^9.1.1", "@types/node": "16.x", + "@types/sinon": "^17.0.2", "@types/vscode": "^1.71.0", "@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/parser": "^5.31.0", - "@vscode/test-electron": "^2.1.5", + "@vscode/test-cli": "^0.0.4", + "@vscode/test-electron": "^2.3.8", "eslint": "^8.20.0", "glob": "^8.0.3", "mocha": "^10.0.0", + "sinon": "^17.0.1", "typescript": "^4.7.4" }, "engines": { @@ -93,6 +96,102 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "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, + "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.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "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, + "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 + }, + "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, + "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, + "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, + "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/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -128,6 +227,60 @@ "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, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -171,6 +324,21 @@ "integrity": "sha512-6u+36Dj3aDzhfBVUf/mfmc92OEdzQ2kx2jcXGdigfl70E/neV21ZHE6UCz4MDzTRcVqGAM27fk+DLXvyDsn3Jw==", "dev": true }, + "node_modules/@types/sinon": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.2.tgz", + "integrity": "sha512-Zt6heIGsdqERkxctIpvN5Pv3edgBrhoeb3yHyxffd4InN0AX2SVNKSrhdDZKGQICVOxWP/q4DyhpfPNMSrpIiA==", + "dev": true, + "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 + }, "node_modules/@types/vscode": { "version": "1.71.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.71.0.tgz", @@ -362,25 +530,142 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "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==", + "node_modules/@vscode/test-cli": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.4.tgz", + "integrity": "sha512-Tx0tfbxeSb2Xlo+jpd+GJrNLgKQHobhRHrYvOipZRZQYWZ82sKiK02VY09UjU1Czc/YnZnqyAnjUfaVGl3h09w==", + "dev": true, + "dependencies": { + "@types/mocha": "^10.0.2", + "chokidar": "^3.5.3", + "glob": "^10.3.10", + "minimatch": "^9.0.3", + "mocha": "^10.2.0", + "supports-color": "^9.4.0", + "yargs": "^17.7.2" + }, + "bin": { + "vscode-test": "out/bin.mjs" + } + }, + "node_modules/@vscode/test-cli/node_modules/@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", "dev": true }, + "node_modules/@vscode/test-cli/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vscode/test-cli/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, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@vscode/test-cli/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/test-cli/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/test-cli/node_modules/supports-color": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", + "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@vscode/test-cli/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, + "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/@vscode/test-cli/node_modules/yargs-parser": { + "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, + "engines": { + "node": ">=12" + } + }, "node_modules/@vscode/test-electron": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", - "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz", + "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==", "dev": true, "dependencies": { "http-proxy-agent": "^4.0.1", "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" + "jszip": "^3.10.1", + "semver": "^7.5.2" }, "engines": { - "node": ">=8.9.3" + "node": ">=16" } }, "node_modules/acorn": { @@ -499,28 +784,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dev": true, - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -530,12 +793,6 @@ "node": ">=8" } }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", - "dev": true - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -564,24 +821,6 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "dev": true, - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -603,18 +842,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dev": true, - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -793,14 +1020,11 @@ "node": ">=6.0.0" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } + "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 }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -1156,6 +1380,22 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1176,53 +1416,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fstream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fstream/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -1325,12 +1518,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, "node_modules/grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", @@ -1391,6 +1578,12 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -1516,6 +1709,24 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-sdsl": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", @@ -1546,6 +1757,24 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1559,11 +1788,14 @@ "node": ">= 0.8.0" } }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", - "dev": true + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } }, "node_modules/locate-path": { "version": "6.0.0", @@ -1580,6 +1812,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1648,31 +1886,21 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", @@ -1813,6 +2041,46 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/nise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1878,6 +2146,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1917,6 +2191,46 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-to-regexp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -1992,9 +2306,9 @@ } }, "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -2143,9 +2457,9 @@ ] }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2193,6 +2507,45 @@ "node": ">=8" } }, + "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, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2231,6 +2584,21 @@ "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, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2243,6 +2611,19 @@ "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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2285,15 +2666,6 @@ "node": ">=8.0" } }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2327,6 +2699,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -2352,24 +2733,6 @@ "node": ">=4.2.0" } }, - "node_modules/unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -2401,9 +2764,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2432,6 +2795,24 @@ "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, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2555,6 +2936,71 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "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.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "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" + } + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2581,6 +3027,59 @@ "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.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -2621,6 +3120,21 @@ "integrity": "sha512-6u+36Dj3aDzhfBVUf/mfmc92OEdzQ2kx2jcXGdigfl70E/neV21ZHE6UCz4MDzTRcVqGAM27fk+DLXvyDsn3Jw==", "dev": true }, + "@types/sinon": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.2.tgz", + "integrity": "sha512-Zt6heIGsdqERkxctIpvN5Pv3edgBrhoeb3yHyxffd4InN0AX2SVNKSrhdDZKGQICVOxWP/q4DyhpfPNMSrpIiA==", + "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 + }, "@types/vscode": { "version": "1.71.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.71.0.tgz", @@ -2723,22 +3237,108 @@ "eslint-visitor-keys": "^3.3.0" } }, - "@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 + "@vscode/test-cli": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.4.tgz", + "integrity": "sha512-Tx0tfbxeSb2Xlo+jpd+GJrNLgKQHobhRHrYvOipZRZQYWZ82sKiK02VY09UjU1Czc/YnZnqyAnjUfaVGl3h09w==", + "dev": true, + "requires": { + "@types/mocha": "^10.0.2", + "chokidar": "^3.5.3", + "glob": "^10.3.10", + "minimatch": "^9.0.3", + "mocha": "^10.2.0", + "supports-color": "^9.4.0", + "yargs": "^17.7.2" + }, + "dependencies": { + "@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true + }, + "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": { + "balanced-match": "^1.0.0" + } + }, + "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" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "supports-color": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", + "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", + "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": "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 + } + } }, "@vscode/test-electron": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", - "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz", + "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==", "dev": true, "requires": { "http-proxy-agent": "^4.0.1", "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" + "jszip": "^3.10.1", + "semver": "^7.5.2" } }, "acorn": { @@ -2824,34 +3424,12 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", - "dev": true - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2877,18 +3455,6 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "dev": true - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2901,15 +3467,6 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3041,14 +3598,11 @@ "esutils": "^2.0.2" } }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "requires": { - "readable-stream": "^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 }, "emoji-regex": { "version": "8.0.0", @@ -3324,6 +3878,16 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3337,43 +3901,6 @@ "dev": true, "optional": true }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -3451,12 +3978,6 @@ "slash": "^3.0.0" } }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, "grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", @@ -3502,6 +4023,12 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3594,6 +4121,16 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "js-sdsl": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", @@ -3621,6 +4158,24 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3631,11 +4186,14 @@ "type-check": "~0.4.0" } }, - "listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", - "dev": true + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } }, "locate-path": { "version": "6.0.0", @@ -3646,6 +4204,12 @@ "p-locate": "^5.0.0" } }, + "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", @@ -3696,28 +4260,18 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, "mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "requires": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", @@ -3826,6 +4380,50 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "nise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + } + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3873,6 +4471,12 @@ "p-limit": "^3.0.2" } }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3900,6 +4504,41 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "dev": true + } + } + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3946,9 +4585,9 @@ } }, "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -4042,9 +4681,9 @@ "dev": true }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -4080,6 +4719,34 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "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": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "dependencies": { + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4114,6 +4781,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" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4123,6 +4801,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-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4153,12 +4840,6 @@ "is-number": "^7.0.0" } }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "dev": true - }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -4183,6 +4864,12 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -4195,24 +4882,6 @@ "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", "dev": true }, - "unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "requires": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4238,9 +4907,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "workerpool": { @@ -4260,6 +4929,17 @@ "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", diff --git a/package.json b/package.json index e6c3954..0c89e9a 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,12 @@ "@types/glob": "^7.2.0", "@types/mocha": "^9.1.1", "@types/node": "16.x", + "@types/sinon": "^17.0.2", "@types/vscode": "^1.71.0", "@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/parser": "^5.31.0", - "@vscode/test-electron": "^2.1.5", + "@vscode/test-cli": "^0.0.4", + "@vscode/test-electron": "^2.3.8", "eslint": "^8.20.0", "glob": "^8.0.3", "mocha": "^10.0.0", diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 6123b8a..0000000 --- a/src/constants.ts +++ /dev/null @@ -1,20 +0,0 @@ -// todo json fΓΌr Konstanten - -// general -export const KEYSTROKE_DEFAULT_VALUE = 0; -export const KEYSTROKE_ERROR_VALUE = -1; - -// icons -export const KEYBOARD_ICON = '$(keyboard)'; -export const FIRST_ICON = 'πŸ₯‡'; -export const SECOND_ICON = 'πŸ₯ˆ'; -export const THIRD_ICON = 'πŸ₯‰'; - -// time -export const SECOND_AS_MILLISECONDS = 1000; -export const MINUTE_AS_MILLISECONDS = SECOND_AS_MILLISECONDS * 60; -export const HOUR_AS_MILLISECONDS = MINUTE_AS_MILLISECONDS * 60; -export const DAY_AS_MILLISECONDS = HOUR_AS_MILLISECONDS * 24; -export const WEEK_AS_MILLISECONDS = DAY_AS_MILLISECONDS * 7; -export const MONTH_AS_MILLISECONDS = DAY_AS_MILLISECONDS * 30; // todo: could be problematic -export const YEAR_AS_MILLISECONDS = MONTH_AS_MILLISECONDS * 12; \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 872451d..c0652fb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,68 +1,119 @@ -import * as vscode from 'vscode'; +import * as vscode from "vscode"; -import { KEYBOARD_ICON, - SECOND_AS_MILLISECONDS, MINUTE_AS_MILLISECONDS, HOUR_AS_MILLISECONDS, DAY_AS_MILLISECONDS, WEEK_AS_MILLISECONDS, MONTH_AS_MILLISECONDS, YEAR_AS_MILLISECONDS, } from "./constants"; -import { getPraisingWord, setLongInterval, } from './utils'; -import { updateStatusBarItem, isValidChangedContent, } from './vscode_utils'; -import { getAverageWordsPerMinute, } from './libs/words_per_minute'; -import { amountsOfKeystrokes, - resetOneTimespanKeystrokesAmount, getThreeMostOftenPressedKeys, getMostOftenPressedKeysMessage, getKeystrokeCountAnalyticsMessage, incrementKeystrokesOfEveryTimespan, collectPressedKey, } from './libs/keystrokes_analytics'; +import { + SECOND_AS_MILLISECONDS, + MINUTE_AS_MILLISECONDS, + HOUR_AS_MILLISECONDS, + DAY_AS_MILLISECONDS, + WEEK_AS_MILLISECONDS, + MONTH_AS_MILLISECONDS, + YEAR_AS_MILLISECONDS, +} from "./libs/constants"; +import { getPressedKey, isValidChangedContent, setLongInterval } from "./libs/utils"; +import { + keystrokeRepository, + getKeystrokeCountAnalyticsMessage, + getThreeMostOftenpressedKeysInDescendingOrderMessage, +} from "./libs/keystroke_analytics_messages"; +import { WordsPerMinuteCalculator } from "./libs/words_per_minute_calculator"; +import { WordsPerMinuteStatusBar } from "./status_bar/words_per_minute_status_bar"; +import { KeystrokCountStatusBar } from "./status_bar/keystroke_count_status_bar"; -export var statusBarItem: vscode.StatusBarItem; +const keystrokeCountAnalyticsCommandId = "keystrokemanager.keystrokeCountAnalytics"; +const mostOftenPressedKeysCommandId = "keystrokemanager.mostOftenPressedKeys"; + +let wpmStatusBar: WordsPerMinuteStatusBar; +let keystrokeCountStatusBar: KeystrokCountStatusBar; export function activate({ subscriptions }: vscode.ExtensionContext): void { - // commands - const keystrokeCountAnalyticsCommandId = 'keystrokemanager.keystrokeCountAnalytics'; - const mostOftenPressedKeysCommandId = 'keystrokemanager.mostOftenPressedKeys'; - - subscriptions.push(vscode.commands.registerCommand(keystrokeCountAnalyticsCommandId, keystrokeCountAnalyticsCommand)); - subscriptions.push(vscode.commands.registerCommand(mostOftenPressedKeysCommandId, mostOftenPressedKeysCommand)); - - // statusBarItem - const STATUS_BAR_ITEM_PRIORITY = 101; - statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, STATUS_BAR_ITEM_PRIORITY); - statusBarItem.command = keystrokeCountAnalyticsCommandId; - statusBarItem.text = `${KEYBOARD_ICON} Keystrokes: ${amountsOfKeystrokes.get('total')} | 0 WPM`; - // todo: add this in future - statusBarItem.tooltip = 'Select Timespan'; - statusBarItem.show(); - subscriptions.push(statusBarItem); - - // change-detections - subscriptions.push(vscode.workspace.onDidChangeTextDocument(updateKeystrokes)); - - // intervals - setInterval(() => { - const wordsPerMinute = getAverageWordsPerMinute(amountsOfKeystrokes); - updateStatusBarItem(amountsOfKeystrokes.get('total'), wordsPerMinute); - - resetOneTimespanKeystrokesAmount('second'); - }, SECOND_AS_MILLISECONDS); - setInterval(() => resetOneTimespanKeystrokesAmount('minute'), MINUTE_AS_MILLISECONDS); - setInterval(() => resetOneTimespanKeystrokesAmount('hour'), HOUR_AS_MILLISECONDS); - setInterval(() => resetOneTimespanKeystrokesAmount('day'), DAY_AS_MILLISECONDS); - setInterval(() => resetOneTimespanKeystrokesAmount('week'), WEEK_AS_MILLISECONDS); - setLongInterval(() => resetOneTimespanKeystrokesAmount('month'), MONTH_AS_MILLISECONDS); - setLongInterval(() => resetOneTimespanKeystrokesAmount('year'), YEAR_AS_MILLISECONDS); + createCommands(subscriptions); + createStatusBarItems(subscriptions); + + subscriptions.push(vscode.workspace.onDidChangeTextDocument(updateKeystrokes)); + + setTimers(); } -function keystrokeCountAnalyticsCommand(): void { - const message = getKeystrokeCountAnalyticsMessage(); +function createCommands(subscriptions: any): void { + subscriptions.push( + vscode.commands.registerCommand( + keystrokeCountAnalyticsCommandId, + keystrokeCountAnalyticsCommand + ) + ); + subscriptions.push( + vscode.commands.registerCommand(mostOftenPressedKeysCommandId, mostOftenPressedKeysCommand) + ); +} - vscode.window.showInformationMessage(`😊 ${getPraisingWord()}! ${message}`); +function keystrokeCountAnalyticsCommand(): void { + const message: string = getKeystrokeCountAnalyticsMessage(); + vscode.window.showInformationMessage(message); } function mostOftenPressedKeysCommand(): void { - const mostOftenPressedKeys = getThreeMostOftenPressedKeys(); - const message = getMostOftenPressedKeysMessage(mostOftenPressedKeys); + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + vscode.window.showInformationMessage(message); +} + +function createStatusBarItems(subscriptions: any): void { + const STATUS_BAR_ITEM_PRIORITY = 101; + + const wpmCalculator = new WordsPerMinuteCalculator(keystrokeRepository); + const wpmStatusBarItem = vscode.window.createStatusBarItem( + vscode.StatusBarAlignment.Right, + STATUS_BAR_ITEM_PRIORITY + ); + wpmStatusBarItem.tooltip = "Average words per minute [total]"; - vscode.window.showInformationMessage(message); + const keystrokeCountStatusBarItem = vscode.window.createStatusBarItem( + vscode.StatusBarAlignment.Right, + STATUS_BAR_ITEM_PRIORITY + 1 + ); + keystrokeCountStatusBarItem.tooltip = "Keystroke count [total]"; + keystrokeCountStatusBarItem.command = keystrokeCountAnalyticsCommandId; + + wpmStatusBar = new WordsPerMinuteStatusBar(wpmCalculator, wpmStatusBarItem); + keystrokeCountStatusBar = new KeystrokCountStatusBar( + keystrokeRepository, + keystrokeCountStatusBarItem + ); + + subscriptions.push(wpmStatusBar); + subscriptions.push(keystrokeCountStatusBar); } - + function updateKeystrokes(event: vscode.TextDocumentChangeEvent): void { - if(isValidChangedContent(event)) { - incrementKeystrokesOfEveryTimespan(); - updateStatusBarItem(amountsOfKeystrokes.get('total')); - collectPressedKey(event); - } -} \ No newline at end of file + if (isValidChangedContent(event)) { + keystrokeCountStatusBar.update(); + + const pressedKey: string = getPressedKey(event); + keystrokeRepository.addPressedKeyToAll(pressedKey); + } +} + +function setTimers(): void { + setInterval(() => { + wpmStatusBar.update(); + + keystrokeRepository.second.reset(); + }, SECOND_AS_MILLISECONDS); + setInterval(() => { + keystrokeRepository.minute.reset(); + }, MINUTE_AS_MILLISECONDS); + setInterval(() => { + keystrokeRepository.hour.reset(); + }, HOUR_AS_MILLISECONDS); + setInterval(() => { + keystrokeRepository.day.reset(); + }, DAY_AS_MILLISECONDS); + setInterval(() => { + keystrokeRepository.week.reset(); + }, WEEK_AS_MILLISECONDS); + setLongInterval(() => { + keystrokeRepository.month.reset(); + }, MONTH_AS_MILLISECONDS); + setLongInterval(() => { + keystrokeRepository.year.reset(); + }, YEAR_AS_MILLISECONDS); +} diff --git a/src/libs/constants.ts b/src/libs/constants.ts new file mode 100644 index 0000000..d627ef3 --- /dev/null +++ b/src/libs/constants.ts @@ -0,0 +1,15 @@ +// icons +export const KEYBOARD_ICON = "$(keyboard)"; +export const FIRST_ICON = "πŸ₯‡"; +export const SECOND_ICON = "πŸ₯ˆ"; +export const THIRD_ICON = "πŸ₯‰"; + +// time +// todo: thinking about different time management solution +export const SECOND_AS_MILLISECONDS = 1000; +export const MINUTE_AS_MILLISECONDS = SECOND_AS_MILLISECONDS * 60; +export const HOUR_AS_MILLISECONDS = MINUTE_AS_MILLISECONDS * 60; +export const DAY_AS_MILLISECONDS = HOUR_AS_MILLISECONDS * 24; +export const WEEK_AS_MILLISECONDS = DAY_AS_MILLISECONDS * 7; +export const MONTH_AS_MILLISECONDS = DAY_AS_MILLISECONDS * 30; +export const YEAR_AS_MILLISECONDS = MONTH_AS_MILLISECONDS * 12; diff --git a/src/libs/keystroke_analytics_messages.ts b/src/libs/keystroke_analytics_messages.ts new file mode 100644 index 0000000..6953557 --- /dev/null +++ b/src/libs/keystroke_analytics_messages.ts @@ -0,0 +1,46 @@ +import { FIRST_ICON, SECOND_ICON, THIRD_ICON } from "./constants"; +import { KeystrokeRepository } from "./keystroke_repository"; + +export const keystrokeRepository = KeystrokeRepository.getInstance(); + +export function getKeystrokeCountAnalyticsMessage(): string { + let message = `😊 ${getPraisingWord()}! `; + message += `You collected so far ${keystrokeRepository.total.count} keystrokes in total.`; + message += ` ${keystrokeRepository.year.count} of them this year,`; + message += ` ${keystrokeRepository.month.count} this month,`; + message += ` ${keystrokeRepository.week.count} this week,`; + message += ` ${keystrokeRepository.day.count} today,`; + message += ` ${keystrokeRepository.hour.count} this hour and`; + message += ` ${keystrokeRepository.minute.count} this minute!`; + + return message; +} + +// randomly generates a praising word based on an array of praising words +function getPraisingWord(): string { + const WORDS = ["Awesome", "Wonderful", "Great", "Fantastic", "Cool"]; + const randomNumber: number = Math.floor(Math.random() * WORDS.length); + + return WORDS[randomNumber]; +} + +export function getThreeMostOftenpressedKeysInDescendingOrderMessage(): string { + if (keystrokeRepository.total.count === 0) { + return "You pressed no keys so far!"; + } + + const placementIcons = [FIRST_ICON, SECOND_ICON, THIRD_ICON]; + + const pressedKeysInDescendingOrder = + keystrokeRepository.getMostOftenPressedKeysInTotalWithCountInDescendingOrder( + placementIcons.length + ); + + const messageParts = Array.from(pressedKeysInDescendingOrder.entries()).map( + ([key, value], index) => { + return `${placementIcons[index]} '${key}' ${value}x`; + } + ); + + return `You pressed ${messageParts.join(", ")}!`; +} diff --git a/src/libs/keystroke_repository.ts b/src/libs/keystroke_repository.ts new file mode 100644 index 0000000..ad8b7bf --- /dev/null +++ b/src/libs/keystroke_repository.ts @@ -0,0 +1,56 @@ +import { KeystrokeTimeSpan } from "./keystroke_timespan"; + +// Manages every time span. +export class KeystrokeRepository { + private static _instance: KeystrokeRepository; + + public second: KeystrokeTimeSpan; + public minute: KeystrokeTimeSpan; + public hour: KeystrokeTimeSpan; + public day: KeystrokeTimeSpan; + public week: KeystrokeTimeSpan; + public month: KeystrokeTimeSpan; + public year: KeystrokeTimeSpan; + public total: KeystrokeTimeSpan; + + public static getInstance(): KeystrokeRepository { + if (!KeystrokeRepository._instance) { + KeystrokeRepository._instance = new KeystrokeRepository(); + } + + return KeystrokeRepository._instance; + } + + private constructor() { + this.second = new KeystrokeTimeSpan(); + this.minute = new KeystrokeTimeSpan(); + this.hour = new KeystrokeTimeSpan(); + this.day = new KeystrokeTimeSpan(); + this.week = new KeystrokeTimeSpan(); + this.month = new KeystrokeTimeSpan(); + this.year = new KeystrokeTimeSpan(); + this.total = new KeystrokeTimeSpan(); + } + + public addPressedKeyToAll(pressedKey: string): void { + this.second.addPressedKey(pressedKey); + this.minute.addPressedKey(pressedKey); + this.hour.addPressedKey(pressedKey); + this.day.addPressedKey(pressedKey); + this.week.addPressedKey(pressedKey); + this.month.addPressedKey(pressedKey); + this.year.addPressedKey(pressedKey); + this.total.addPressedKey(pressedKey); + } + + public getMostOftenPressedKeysInTotalWithCountInDescendingOrder( + targetSize: number + ): Map { + const entries = Array.from(this.total.pressedKeys.entries()); + entries.sort((left, right) => right[1] - left[1]); + + const topEntriesMap = new Map(entries.slice(0, targetSize)); + + return topEntriesMap; + } +} diff --git a/src/libs/keystroke_timespan.ts b/src/libs/keystroke_timespan.ts new file mode 100644 index 0000000..f00ac3e --- /dev/null +++ b/src/libs/keystroke_timespan.ts @@ -0,0 +1,52 @@ +const ENTER_CHARACTER: string = "\r\n"; +const BACKSPACE_CHARACTER: string = ""; +const TAB_CHARACTER: string = " "; +const SPACE_CHARACTER: string = " "; + +// Managing time spans for key strokes. +export class KeystrokeTimeSpan { + private _pressedKeys: Map; + + constructor(pressedKeys: Map = new Map()) { + this._pressedKeys = pressedKeys; + } + + public addPressedKey(pressedKey: string): void { + const pressedKeyDefaultCount: number = 0; + const previousCount: number = this._pressedKeys.get(pressedKey) ?? pressedKeyDefaultCount; + + const correctKeyLabel: string = this.getCorrectKeyLabel(pressedKey); + this._pressedKeys.set(correctKeyLabel, previousCount + 1); + } + + private getCorrectKeyLabel(key: string): string { + if (key === ENTER_CHARACTER) { + return "Enter"; + } else if (key === BACKSPACE_CHARACTER) { + return "Backspace"; + } else if (key === TAB_CHARACTER) { + return "Tab"; + } else if (key === SPACE_CHARACTER) { + return "Space"; + } + + return key; + } + + public reset(): void { + this._pressedKeys.clear(); + } + + public get pressedKeys(): Map { + return this._pressedKeys; + } + + public get count(): number { + let count: number = 0; + for (const value of this._pressedKeys.values()) { + count += value; + } + + return count; + } +} diff --git a/src/libs/keystrokes_analytics.ts b/src/libs/keystrokes_analytics.ts deleted file mode 100644 index 32698f8..0000000 --- a/src/libs/keystrokes_analytics.ts +++ /dev/null @@ -1,83 +0,0 @@ -import * as vscode from 'vscode'; - -import { KEYSTROKE_DEFAULT_VALUE, - FIRST_ICON, SECOND_ICON, THIRD_ICON, } from "../constants"; - -// todo: using interfaces instead of maps -// interface fΓΌr Datenstruktur von map verwenden -// damit kann ich das auch in json speichern -// test = { -// key: 5; -// }; -// test['key']; - -export const amountsOfKeystrokes = new Map([ - ['second', KEYSTROKE_DEFAULT_VALUE], - ['minute', KEYSTROKE_DEFAULT_VALUE], - ['hour', KEYSTROKE_DEFAULT_VALUE], - ['day', KEYSTROKE_DEFAULT_VALUE], - ['week', KEYSTROKE_DEFAULT_VALUE], - ['month', KEYSTROKE_DEFAULT_VALUE], - ['year', KEYSTROKE_DEFAULT_VALUE], - ['total', KEYSTROKE_DEFAULT_VALUE], -]); -const pressedKeys = new Map(); - -// message for the keystrokeCountAnalyticsCommand -export function getKeystrokeCountAnalyticsMessage(): string { - const keystrokes = amountsOfKeystrokes; - const message = `You collected so far ${keystrokes.get('total')} keystrokes in total. - ${keystrokes.get('year')} of them this year, - ${keystrokes.get('month')} this month, - ${keystrokes.get('week')} this week, - ${keystrokes.get('day')} today, - ${keystrokes.get('hour')} this hour and - ${keystrokes.get('minute')} this minute!`; - - return message; -} - -// message for the mostOftenPressedKeysCommand -export function getMostOftenPressedKeysMessage(keyMap: Map): string { - var message = 'You pressed '; - - const placementIcons = [ FIRST_ICON, SECOND_ICON, THIRD_ICON ]; - let placement = 1; - - // todo map.iterator - - keyMap.forEach((value, key) => { - message += `${placementIcons[placement]} '${key}' ${value} times `; - placement++; - }); - - return message.toString(); -} - -// increments the count of the pressed key -export function collectPressedKey(event: vscode.TextDocumentChangeEvent): void { - const pressedKey = event.contentChanges[0].text; - const prevCount = pressedKeys.get(pressedKey) ?? KEYSTROKE_DEFAULT_VALUE; - - pressedKeys.set(pressedKey, prevCount + 1); -} - -// takes the 3 keys, that have the highest count and returns them -export function getThreeMostOftenPressedKeys(): Map { - const pressedKeysSortedDescending = new Map([...pressedKeys].sort((prev, curr) => prev[1] - curr[1]).reverse()); - - const targetSize = 3; - const mostOftenPressedKeys = new Map([...pressedKeysSortedDescending].slice(0, targetSize)); - - return mostOftenPressedKeys; -} - -// the count of every map-item is incremented -export function incrementKeystrokesOfEveryTimespan(): void { - amountsOfKeystrokes.forEach((value, key, map) => map.set(key, value + 1)); -} - -// the count of one specific map-item is resetted based on the key -export function resetOneTimespanKeystrokesAmount(key: string): void { - amountsOfKeystrokes.set(key, KEYSTROKE_DEFAULT_VALUE); -} diff --git a/src/libs/utils.ts b/src/libs/utils.ts new file mode 100644 index 0000000..3b4d20f --- /dev/null +++ b/src/libs/utils.ts @@ -0,0 +1,33 @@ +import * as vscode from "vscode"; + +// makes it possible to use the setInterval()-method +// for a longer interval than 2^31 - 1 (= 2147483647) seconds +// when using the normal setInterval()-method, than just 0 is used as value, +// if value is greater 2^31 - 1 +export function setLongInterval(callback: any, timeout: number): any { + let count = 0; + const MAX_32_BIT_SIGNED = 2147483647; + const maxIterations = timeout / MAX_32_BIT_SIGNED; + + const onInterval = () => { + count++; + if (count > maxIterations) { + count = 0; + callback(); + } + }; + + return setInterval(onInterval, Math.min(timeout, MAX_32_BIT_SIGNED)); +} + +// checks if the changes in the active document of vscode are valid +// the last check is because of the first change in the document at the beginning +// -> otherwise the keystrokeCount is 'instantly' counting to 2 +export function isValidChangedContent(event: vscode.TextDocumentChangeEvent): boolean { + return event && event.contentChanges && event.contentChanges[0].text !== undefined; +} + +export function getPressedKey(event: vscode.TextDocumentChangeEvent): string { + const key = event.contentChanges[0].text; + return key; +} diff --git a/src/libs/words_per_minute.ts b/src/libs/words_per_minute.ts deleted file mode 100644 index 3c9daa2..0000000 --- a/src/libs/words_per_minute.ts +++ /dev/null @@ -1,38 +0,0 @@ -var wordsPerMinuteEstimations = new Array(); - -// calculates a wpm-value based on an array, that remembers every value of the last 60 seconds -export function getAverageWordsPerMinute(keystrokes: Map): number { - const keystrokesPerSecond = keystrokes.get('second'); - if(keystrokesPerSecond === undefined) { - return 0; - } - - const wordsPerMinuteEstimation = getEstimatedWordsPerMinuteBasedOnOneSecond(keystrokesPerSecond); - console.log('estimation: ' + wordsPerMinuteEstimation); - handleWordsPerMinuteEstimations(wordsPerMinuteEstimation); - console.log(wordsPerMinuteEstimations); - - const averageWordsPerMinute = wordsPerMinuteEstimations.reduce((prev, curr) => prev + curr) / wordsPerMinuteEstimations.length; - console.log('average: ' + averageWordsPerMinute); - const roundedAverageWordsPerMinute = Number(averageWordsPerMinute.toFixed(2)); - - return roundedAverageWordsPerMinute; -} - -// calculates an estimation for the whole minute based on the second -// keystrokesPerSecond / 5 -> one word is on average 5 chars long -// [...] * 60 -> estimation, that this rate is for the next 60 seconds -export function getEstimatedWordsPerMinuteBasedOnOneSecond(keystrokesPerSecond: number): number { - return (keystrokesPerSecond / 5) * 60; -} - -// checks if there are too much estimations in the array -// -> only allowed to keep the last 5 seconds -export function handleWordsPerMinuteEstimations(estimation: number): void { - const REMEMBER_VALUES_COUNT = 5; - - if(wordsPerMinuteEstimations.length === REMEMBER_VALUES_COUNT) { - wordsPerMinuteEstimations.shift(); - } - wordsPerMinuteEstimations.push(estimation); -} \ No newline at end of file diff --git a/src/libs/words_per_minute_calculator.ts b/src/libs/words_per_minute_calculator.ts new file mode 100644 index 0000000..44d3ad7 --- /dev/null +++ b/src/libs/words_per_minute_calculator.ts @@ -0,0 +1,25 @@ +import { KeystrokeRepository } from "./keystroke_repository"; + +// Calculates the average words per minute +export class WordsPerMinuteCalculator { + private _repository: KeystrokeRepository; + // todo: this is a little hack to get the average words per minute working for now + private _totalTimeCalled: number = 0; + + constructor(repository: KeystrokeRepository) { + this._repository = repository; + } + + public getAverageWordsPerMinute(): number { + ++this._totalTimeCalled; + + const totalWordCount = this.getWordCountFromKeyCount(this._repository.total.count); + const wpm = (totalWordCount / this._totalTimeCalled) * 60; + return wpm; + } + + private getWordCountFromKeyCount(keyCount: number): number { + const AVERAGE_WORD_LENGTH: number = 5; + return keyCount / AVERAGE_WORD_LENGTH; + } +} diff --git a/src/status_bar/keystroke_count_status_bar.ts b/src/status_bar/keystroke_count_status_bar.ts new file mode 100644 index 0000000..57f543e --- /dev/null +++ b/src/status_bar/keystroke_count_status_bar.ts @@ -0,0 +1,26 @@ +import * as vscode from "vscode"; +import { KeystrokeRepository } from "../libs/keystroke_repository"; +import { KEYBOARD_ICON } from "../libs/constants"; + +// Shows the total keystrokes in the status bar +export class KeystrokCountStatusBar { + private _keystrokeRepository: KeystrokeRepository; + private _statusBarItem: vscode.StatusBarItem; + + constructor(keystrokeRepository: KeystrokeRepository, statusBarItem: vscode.StatusBarItem) { + this._keystrokeRepository = keystrokeRepository; + this._statusBarItem = statusBarItem; + + this._statusBarItem.text = `${KEYBOARD_ICON} 0`; + this._statusBarItem.show(); + } + + public update(): void { + const totalCount: number = this._keystrokeRepository.total.count; + this._statusBarItem.text = `${KEYBOARD_ICON} ${totalCount}`; + } + + dispose() { + this._statusBarItem.dispose(); + } +} diff --git a/src/status_bar/words_per_minute_status_bar.ts b/src/status_bar/words_per_minute_status_bar.ts new file mode 100644 index 0000000..6586fac --- /dev/null +++ b/src/status_bar/words_per_minute_status_bar.ts @@ -0,0 +1,27 @@ +import * as vscode from "vscode"; +import { WordsPerMinuteCalculator } from "../libs/words_per_minute_calculator"; + +const DIGIT_PRECISION: number = 1; + +// Shows the average words per minute in the status bar +export class WordsPerMinuteStatusBar { + private _wpmCalculator: WordsPerMinuteCalculator; + private _statusBarItem: vscode.StatusBarItem; + + constructor(wpmCalculator: WordsPerMinuteCalculator, statusBarItem: vscode.StatusBarItem) { + this._wpmCalculator = wpmCalculator; + this._statusBarItem = statusBarItem; + + this._statusBarItem.text = `0.0 wpm`; + this._statusBarItem.show(); + } + + public update(): void { + const wpm: number = this._wpmCalculator.getAverageWordsPerMinute(); + this._statusBarItem.text = `${wpm.toFixed(DIGIT_PRECISION)} wpm`; + } + + dispose() { + this._statusBarItem.dispose(); + } +} diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 4ca0ab4..e147255 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,15 +1,15 @@ -import * as assert from 'assert'; +import * as assert from "assert"; // You can import and use all API from the 'vscode' module // as well as import your extension to test it -import * as vscode from 'vscode'; -// import * as myExtension from '../../extension'; +import * as vscode from "vscode"; +import * as ext from "../../extension"; -suite('Extension Test Suite', () => { - vscode.window.showInformationMessage('Start all tests.'); +suite("Extension Test Suite", () => { + vscode.window.showInformationMessage("Start all tests."); - test('Sample test', () => { - assert.strictEqual(-1, [1, 2, 3].indexOf(5)); - assert.strictEqual(-1, [1, 2, 3].indexOf(0)); - }); + test("Sample test", () => { + assert.strictEqual(-1, [1, 2, 3].indexOf(5)); + assert.strictEqual(-1, [1, 2, 3].indexOf(0)); + }); }); diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 7029e38..2cb7d7d 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,38 +1,38 @@ -import * as path from 'path'; -import * as Mocha from 'mocha'; -import * as glob from 'glob'; +import * as path from "path"; +import * as Mocha from "mocha"; +import * as glob from "glob"; export function run(): Promise { - // Create the mocha test - const mocha = new Mocha({ - ui: 'tdd', - color: true - }); + // Create the mocha test + const mocha = new Mocha({ + ui: "tdd", + color: true, + }); - const testsRoot = path.resolve(__dirname, '..'); + const testsRoot = path.resolve(__dirname, ".."); - return new Promise((c, e) => { - glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } + return new Promise((c, e) => { + glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { + if (err) { + return e(err); + } - // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); + // Add files to the test suite + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); - try { - // Run the mocha test - mocha.run(failures => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - console.error(err); - e(err); - } - }); - }); + try { + // Run the mocha test + mocha.run((failures) => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); + } + }); + } catch (err) { + console.error(err); + e(err); + } + }); + }); } diff --git a/src/test/suite/keystroke_analytics_messages.test.ts b/src/test/suite/keystroke_analytics_messages.test.ts new file mode 100644 index 0000000..aeb2ddd --- /dev/null +++ b/src/test/suite/keystroke_analytics_messages.test.ts @@ -0,0 +1,102 @@ +import * as assert from "assert"; +import { KeystrokeRepository } from "../../libs/keystroke_repository"; +import { resetKeystrokeRepository } from "../test_utils"; +import { + getKeystrokeCountAnalyticsMessage, + getThreeMostOftenpressedKeysInDescendingOrderMessage, +} from "../../libs/keystroke_analytics_messages"; + +suite("KeystrokeAnalyticsMessages Test Suite", () => { + let repository: KeystrokeRepository; + + setup(() => { + repository = KeystrokeRepository.getInstance(); + }); + + teardown(() => { + resetKeystrokeRepository(repository); + }); + + test("getKeystrokeCountAnalyticsMessage() returns the correct message", () => { + repository.addPressedKeyToAll("a"); + const expectedPattern = + /😊 (.*)! You collected so far 1 keystrokes in total. 1 of them this year, 1 this month, 1 this week, 1 today, 1 this hour and 1 this minute!/; + + const message: string = getKeystrokeCountAnalyticsMessage(); + + assert.match(message, expectedPattern); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the correct message", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("b"); + repository.addPressedKeyToAll("b"); + repository.addPressedKeyToAll("b"); + repository.addPressedKeyToAll("c"); + repository.addPressedKeyToAll("c"); + repository.addPressedKeyToAll("d"); + + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, `You pressed πŸ₯‡ 'a' 4x, πŸ₯ˆ 'b' 3x, πŸ₯‰ 'c' 2x!`); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the correct message when there is only one pressed key", () => { + repository.addPressedKeyToAll("a"); + + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, `You pressed πŸ₯‡ 'a' 1x!`); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the correct message when there are less than 3 pressed keys", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("b"); + + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, `You pressed πŸ₯‡ 'a' 2x, πŸ₯ˆ 'b' 1x!`); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the correct message when there are no pressed keys", () => { + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, "You pressed no keys so far!"); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the word 'Enter' when the key 'Enter' got pressed", () => { + repository.addPressedKeyToAll("\r\n"); + + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, `You pressed πŸ₯‡ 'Enter' 1x!`); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the word 'Tab' when the key 'Tab' got pressed", () => { + repository.addPressedKeyToAll(" "); + + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, `You pressed πŸ₯‡ 'Tab' 1x!`); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the word 'Space' when the key 'Space' got pressed", () => { + repository.addPressedKeyToAll(" "); + + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, `You pressed πŸ₯‡ 'Space' 1x!`); + }); + + test("getThreeMostOftenpressedKeysInDescendingOrderMessage() returns the word 'Backspace' when the key 'Backspace' got pressed", () => { + repository.addPressedKeyToAll(""); + + const message: string = getThreeMostOftenpressedKeysInDescendingOrderMessage(); + + assert.strictEqual(message, `You pressed πŸ₯‡ 'Backspace' 1x!`); + }); +}); diff --git a/src/test/suite/keystroke_count_status_bar.test.ts b/src/test/suite/keystroke_count_status_bar.test.ts new file mode 100644 index 0000000..9dd7395 --- /dev/null +++ b/src/test/suite/keystroke_count_status_bar.test.ts @@ -0,0 +1,40 @@ +import * as assert from "assert"; +import { KeystrokeRepository } from "../../libs/keystroke_repository"; +import { resetKeystrokeRepository } from "../test_utils"; +import * as vscode from "vscode"; +import { KeystrokCountStatusBar } from "../../status_bar/keystroke_count_status_bar"; +import { KEYBOARD_ICON } from "../../libs/constants"; + +suite("KeystrokeCountStatusBar Test Suite", () => { + let repository: KeystrokeRepository; + let statusBarItem: vscode.StatusBarItem; + let statusBar: KeystrokCountStatusBar; + + setup(() => { + repository = KeystrokeRepository.getInstance(); + statusBarItem = vscode.window.createStatusBarItem(); + statusBar = new KeystrokCountStatusBar(repository, statusBarItem); + }); + + teardown(() => { + resetKeystrokeRepository(repository); + }); + + test("Update() sets the text of the status bar item properly", () => { + statusBar.update(); + + assert.strictEqual(statusBar["_statusBarItem"].text, `${KEYBOARD_ICON} 0`); + }); + + test("Update() should set the text of the status bar item to '5' after addPressedKeyToAll() got called 5 times", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + + statusBar.update(); + + assert.strictEqual(statusBar["_statusBarItem"].text, `${KEYBOARD_ICON} 5`); + }); +}); diff --git a/src/test/suite/keystroke_repository.test.ts b/src/test/suite/keystroke_repository.test.ts new file mode 100644 index 0000000..a1d16b6 --- /dev/null +++ b/src/test/suite/keystroke_repository.test.ts @@ -0,0 +1,95 @@ +import * as assert from "assert"; +import { KeystrokeRepository } from "../../libs/keystroke_repository"; +import { resetKeystrokeRepository } from "../test_utils"; + +suite("KeystrokeRepository Test Suite", () => { + let repository: KeystrokeRepository; + + setup(() => { + repository = KeystrokeRepository.getInstance(); + }); + + teardown(() => { + resetKeystrokeRepository(repository); + }); + + test("getInstance() returns the same instance", () => { + assert.strictEqual(repository, KeystrokeRepository.getInstance()); + }); + + test("Initial count is 0", () => { + assert.strictEqual(repository.second.count, 0); + assert.strictEqual(repository.minute.count, 0); + assert.strictEqual(repository.hour.count, 0); + assert.strictEqual(repository.day.count, 0); + assert.strictEqual(repository.week.count, 0); + assert.strictEqual(repository.month.count, 0); + assert.strictEqual(repository.year.count, 0); + assert.strictEqual(repository.total.count, 0); + }); + + test("AddPressedKeyToAll() increases count by 1 for every timeSpan", () => { + repository.addPressedKeyToAll("a"); + + assert.strictEqual(repository.second.count, 1); + assert.strictEqual(repository.minute.count, 1); + assert.strictEqual(repository.hour.count, 1); + assert.strictEqual(repository.day.count, 1); + assert.strictEqual(repository.week.count, 1); + assert.strictEqual(repository.month.count, 1); + assert.strictEqual(repository.year.count, 1); + assert.strictEqual(repository.total.count, 1); + }); + + test("AddPressedKeyToAll() once with 'a' adds pressedKey to every timeSpan exactly one time", () => { + repository.addPressedKeyToAll("a"); + + assert.strictEqual(repository.second.pressedKeys.get("a"), 1); + assert.strictEqual(repository.minute.pressedKeys.get("a"), 1); + assert.strictEqual(repository.hour.pressedKeys.get("a"), 1); + assert.strictEqual(repository.day.pressedKeys.get("a"), 1); + assert.strictEqual(repository.week.pressedKeys.get("a"), 1); + assert.strictEqual(repository.month.pressedKeys.get("a"), 1); + assert.strictEqual(repository.year.pressedKeys.get("a"), 1); + assert.strictEqual(repository.total.pressedKeys.get("a"), 1); + }); + + test("AddPressedKeyToAll() twice with 'a' adds pressedKey to every timeSpan exactly two times", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + + assert.strictEqual(repository.second.pressedKeys.get("a"), 2); + assert.strictEqual(repository.minute.pressedKeys.get("a"), 2); + assert.strictEqual(repository.hour.pressedKeys.get("a"), 2); + assert.strictEqual(repository.day.pressedKeys.get("a"), 2); + assert.strictEqual(repository.week.pressedKeys.get("a"), 2); + assert.strictEqual(repository.month.pressedKeys.get("a"), 2); + assert.strictEqual(repository.year.pressedKeys.get("a"), 2); + assert.strictEqual(repository.total.pressedKeys.get("a"), 2); + }); + + test("getMostOftenPressedKeysInTotalWithCountInDescendingOrder() returns the pressedKeys sorted descending", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("b"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("b"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("c"); + + // idk why, but for comparison the Map needs to be converted to an array + const mostOftenPressedKeys = Array.from( + repository.getMostOftenPressedKeysInTotalWithCountInDescendingOrder( + repository.total.pressedKeys.size + ) + ); + const expected = Array.from( + new Map([ + ["a", 3], + ["b", 2], + ["c", 1], + ]) + ); + + assert.deepStrictEqual(mostOftenPressedKeys, expected); + }); +}); diff --git a/src/test/suite/keystroke_timespan.test.ts b/src/test/suite/keystroke_timespan.test.ts new file mode 100644 index 0000000..bb2f0e6 --- /dev/null +++ b/src/test/suite/keystroke_timespan.test.ts @@ -0,0 +1,80 @@ +import * as assert from "assert"; +import { KeystrokeTimeSpan } from "../../libs/keystroke_timespan"; + +suite("KeystrokeTimeSpan Test Suite", () => { + let timeSpan: KeystrokeTimeSpan; + + setup(() => { + timeSpan = new KeystrokeTimeSpan(); + }); + + test("Initial count is 0", () => { + assert.strictEqual(timeSpan.count, 0); + }); + + test("Initial pressedKeys is empty", () => { + assert.strictEqual(timeSpan.pressedKeys.size, 0); + }); + + test("When initialized with a map, the count is the sum of the values in the map", () => { + const pressedKeys = new Map(); + pressedKeys.set("a", 1); + pressedKeys.set("b", 2); + pressedKeys.set("c", 3); + + const timeSpan = new KeystrokeTimeSpan(pressedKeys); + + assert.strictEqual(timeSpan.count, 6); + }); + + test("AddPressedKey() for 'a' once, so the count is 1", () => { + timeSpan.addPressedKey("a"); + + assert.strictEqual(timeSpan.count, 1); + }); + + test("AddPressedKey() for 'a' once, so the count for the key 'a' is 1 and only 1 element is in the map", () => { + timeSpan.addPressedKey("a"); + + assert.strictEqual(timeSpan.pressedKeys.size, 1); + assert.strictEqual(timeSpan.pressedKeys.get("a"), 1); + }); + + test("AddPressedKey() for 'a' twice, so the count for the key 'a' is 2 and only 1 element is in the map", () => { + timeSpan.addPressedKey("a"); + timeSpan.addPressedKey("a"); + + assert.strictEqual(timeSpan.pressedKeys.size, 1); + assert.strictEqual(timeSpan.pressedKeys.get("a"), 2); + }); + + test("AddPressedKey() for 'a' once and 'b' once, so the count for the key 'a' and 'b' is 1 and 2 elements are in the map", () => { + timeSpan.addPressedKey("a"); + timeSpan.addPressedKey("b"); + + assert.strictEqual(timeSpan.pressedKeys.size, 2); + assert.strictEqual(timeSpan.pressedKeys.get("a"), 1); + assert.strictEqual(timeSpan.pressedKeys.get("b"), 1); + }); + + test("AddPressedKey() handles special key labels correctly (Enter, Space, Tab, Backspace)", () => { + timeSpan.addPressedKey("\r\n"); + timeSpan.addPressedKey(""); + timeSpan.addPressedKey(" "); + timeSpan.addPressedKey(" "); + + assert.strictEqual(timeSpan.pressedKeys.size, 4); + assert.strictEqual(timeSpan.pressedKeys.get("Enter"), 1); + assert.strictEqual(timeSpan.pressedKeys.get("Backspace"), 1); + assert.strictEqual(timeSpan.pressedKeys.get("Tab"), 1); + assert.strictEqual(timeSpan.pressedKeys.get("Space"), 1); + }); + + test("reset() clears all elements in the map", () => { + timeSpan.addPressedKey("a"); + timeSpan.addPressedKey("b"); + timeSpan.reset(); + + assert.strictEqual(timeSpan.pressedKeys.size, 0); + }); +}); diff --git a/src/test/suite/words_per_minute_calculator.test.ts b/src/test/suite/words_per_minute_calculator.test.ts new file mode 100644 index 0000000..39e27cc --- /dev/null +++ b/src/test/suite/words_per_minute_calculator.test.ts @@ -0,0 +1,48 @@ +import * as assert from "assert"; +import { KeystrokeRepository } from "../../libs/keystroke_repository"; +import { WordsPerMinuteCalculator } from "../../libs/words_per_minute_calculator"; +import { resetKeystrokeRepository } from "../test_utils"; + +suite("WordsPerMinuteCalculator Test Suite", () => { + let repository: KeystrokeRepository; + let calculator: WordsPerMinuteCalculator; + + setup(() => { + repository = KeystrokeRepository.getInstance(); + calculator = new WordsPerMinuteCalculator(repository); + }); + + teardown(() => { + resetKeystrokeRepository(repository); + }); + + test("GetAverageWordsPerMinute() returns 0 when no key is pressed", () => { + const wpm = calculator.getAverageWordsPerMinute(); + assert.strictEqual(wpm, 0); + }); + + test("GetAverageWordsPerMinute() returns 60 when 5 keys are pressed (5 charactes are equal to 1 word)", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + + const wpm = calculator.getAverageWordsPerMinute(); + assert.strictEqual(wpm, 60); + }); + + test("GetAverageWordsPerMinute() returns 60 when 5 keys were pressed and at the second time without touching any further keys, it returns 30", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + + const wpm1 = calculator.getAverageWordsPerMinute(); + assert.strictEqual(wpm1, 60); + + const wpm2 = calculator.getAverageWordsPerMinute(); + assert.strictEqual(wpm2, 30); + }); +}); diff --git a/src/test/suite/words_per_minute_status_bar.test.ts b/src/test/suite/words_per_minute_status_bar.test.ts new file mode 100644 index 0000000..cfbf4a3 --- /dev/null +++ b/src/test/suite/words_per_minute_status_bar.test.ts @@ -0,0 +1,42 @@ +import * as assert from "assert"; +import { KeystrokeRepository } from "../../libs/keystroke_repository"; +import { WordsPerMinuteCalculator } from "../../libs/words_per_minute_calculator"; +import { resetKeystrokeRepository } from "../test_utils"; +import { WordsPerMinuteStatusBar } from "../../status_bar/words_per_minute_status_bar"; +import * as vscode from "vscode"; + +suite("WordsPerMinuteStatusBar Test Suite", () => { + let repository: KeystrokeRepository; + let calculator: WordsPerMinuteCalculator; + let statusBarItem: vscode.StatusBarItem; + let statusBar: WordsPerMinuteStatusBar; + + setup(() => { + repository = KeystrokeRepository.getInstance(); + calculator = new WordsPerMinuteCalculator(repository); + statusBarItem = vscode.window.createStatusBarItem(); + statusBar = new WordsPerMinuteStatusBar(calculator, statusBarItem); + }); + + teardown(() => { + resetKeystrokeRepository(repository); + }); + + test("Update() sets the text of the status bar item properly", () => { + statusBar.update(); + + assert.strictEqual(statusBar["_statusBarItem"].text, "0.0 wpm"); + }); + + test("Update() should set the text of the status bar item to '60.0 wpm' after addPressedKeyToAll() got called 5 times", () => { + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + repository.addPressedKeyToAll("a"); + + statusBar.update(); + + assert.strictEqual(statusBar["_statusBarItem"].text, "60.0 wpm"); + }); +}); diff --git a/src/test/test_utils.ts b/src/test/test_utils.ts new file mode 100644 index 0000000..e69a78c --- /dev/null +++ b/src/test/test_utils.ts @@ -0,0 +1,12 @@ +import { KeystrokeRepository } from "../libs/keystroke_repository"; + +export function resetKeystrokeRepository(repository: KeystrokeRepository): void { + repository.second.reset(); + repository.minute.reset(); + repository.hour.reset(); + repository.day.reset(); + repository.week.reset(); + repository.month.reset(); + repository.year.reset(); + repository.total.reset(); +} diff --git a/src/utils.ts b/src/utils.ts deleted file mode 100644 index 998abd7..0000000 --- a/src/utils.ts +++ /dev/null @@ -1,26 +0,0 @@ -// randomly generates a praising word based on an array of praising words -export function getPraisingWord(): string { - const WORDS = ['Awesome', 'Wonderful', 'Great', 'Fantastic', 'Cool']; - - return WORDS[Math.floor(Math.random() * WORDS.length)]; -} - -// makes it possible to use the setInterval()-method -// for a longer interval than 2^31 - 1 (= 2147483647) seconds -// when using the normal setInterval()-method, than just 0 is used as value, -// if value is greater 2^31 - 1 -export function setLongInterval(callback: any, timeout: number): any { - let count = 0; - const MAX_32_BIT_SIGNED = 2147483647; - const maxIterations = timeout / MAX_32_BIT_SIGNED; - - const onInterval = () => { - count++; - if (count > maxIterations) { - count = 0; - callback(); - } - }; - - return setInterval(onInterval, Math.min(timeout, MAX_32_BIT_SIGNED)); -}; \ No newline at end of file diff --git a/src/vscode_utils.ts b/src/vscode_utils.ts deleted file mode 100644 index 1bb8d46..0000000 --- a/src/vscode_utils.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as vscode from 'vscode'; - -import { statusBarItem } from './extension'; -import { KEYSTROKE_ERROR_VALUE, - KEYBOARD_ICON, } from './constants'; - -var lastWordsPerMinuteValue = 0; - -// updates the keystroke- and wordsPerMinute-value of the statusBarItem -// if there is no wordsPerMinute-value, then it just uses the last one, that was fetched -export function updateStatusBarItem(keystrokesValue: number = KEYSTROKE_ERROR_VALUE, wordsPerMinute: number = lastWordsPerMinuteValue): void { - statusBarItem.text = `${KEYBOARD_ICON} Keystrokes: ${keystrokesValue} | ${wordsPerMinute} WPM`; - lastWordsPerMinuteValue = wordsPerMinute; -} - -// checks if the changes in the active document of vscode are valid -// the last check is because of the first change in the document at the beginning -// -> otherwise the keystrokeCount is 'instantly' counting to 2 -export function isValidChangedContent(event: vscode.TextDocumentChangeEvent): boolean { - return event && - event.contentChanges && - event.contentChanges[0].text !== undefined; -}; \ No newline at end of file