diff --git a/.github/workflows/github-action-test-python.yml b/.github/workflows/github-action-test-python.yml index 39280c9c..2d3f963b 100644 --- a/.github/workflows/github-action-test-python.yml +++ b/.github/workflows/github-action-test-python.yml @@ -22,3 +22,7 @@ jobs: - name: Test run: | cd python && ./allTestsForPyVersion + - name: Test pytrace-generator + run: | + python3 python/src/runYourProgram.py --install-mode installOnly + python3 pytrace-generator/test/runTests.py diff --git a/.vscodeignore b/.vscodeignore index 37785fda..3185608a 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -15,3 +15,4 @@ python/deps/untypy/examples/** python/tests/* python/file-tests/* python/integration-tests/* +pytrace-generator/test/** diff --git a/README.md b/README.md index aac28b8f..5db54df7 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,7 @@ Please report them in the [issue tracker](https://github.com/skogsbaer/write-you You can debug the extension from Visual Studio Code: +* `npm install` * Open the main folder of the plugin with vscode. * Open the file `extension.ts`. * Choose "Run" from the menu, then "Start Debugging". diff --git a/package-lock.json b/package-lock.json index 47dde11f..5f77e805 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,134 +8,256 @@ "name": "write-your-python-program", "version": "1.1.0", "license": "See license in LICENSE", + "dependencies": { + "@types/node": "^18.11.13", + "leader-line": "^1.0.7", + "stringify-json": "^2.0.0", + "tmp": "^0.2.3", + "ts-md5": "^1.3.1" + }, "devDependencies": { - "@types/glob": "^7.1.4", "@types/mocha": "^8.2.3", - "@types/node": "^14.17.18", - "@types/vscode": "^1.49.0", - "@typescript-eslint/eslint-plugin": "^4.31.2", - "@typescript-eslint/parser": "^4.31.2", - "eslint": "^7.32.0", - "glob": "^7.2.0", - "mocha": "^8.4.0", - "typescript": "^4.4.3", - "vscode-test": "^1.6.1" + "@types/node": "^18.11.13", + "@types/tmp": "^0.2.6", + "@types/vscode": "^1.85.0", + "@typescript-eslint/eslint-plugin": "^5.30.0", + "@typescript-eslint/parser": "^5.30.0", + "@vscode/test-electron": "^1.6.1", + "eslint": "^8.18.0", + "glob": "^11.0.0", + "mocha": "^10.7.3", + "typescript": "^5.4.2" }, "engines": { - "vscode": "^1.49.0" + "vscode": "^1.85.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.10.4" + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "node_modules/@eslint-community/regexpp": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=6.9.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=4" + "node": "*" } }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10.10.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">= 4" + "node": "*" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10.10.0" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "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", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -149,6 +271,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -158,6 +281,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -175,27 +299,12 @@ "node": ">= 6" } }, - "node_modules/@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/mocha": { "version": "8.2.3", @@ -204,41 +313,64 @@ "dev": true }, "node_modules/@types/node": { - "version": "14.17.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.18.tgz", - "integrity": "sha512-haYyibw4pbteEhkSg0xdDLAI3679L75EJ799ymVrPxOA922bPx3ML59SoDsQ//rHlvqpu+e36kcbR3XRQtFblA==", - "dev": true + "version": "18.19.51", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.51.tgz", + "integrity": "sha512-IIMkWEIVQDlBpi6pPeGqTqOx7KbzGC3EgIyH8NrxplXOwWw0uVl9vthJUMFrxD7kcEfcRp7jIkgpB28M6JnfWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tmp": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", + "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/vscode": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.60.0.tgz", - "integrity": "sha512-wZt3VTmzYrgZ0l/3QmEbCq4KAJ71K3/hmMQ/nfpv84oH8e81KKwPEoQ5v8dNCxfHFVJ1JabHKmCvqdYOoVm1Ow==", - "dev": true + "version": "1.93.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.93.0.tgz", + "integrity": "sha512-kUK6jAHSR5zY8ps42xuW89NLcBpw1kOabah7yv38J8MyiYuOHxLQBi0e7zeXbQgVefDy/mZZetqEFC+Fl5eIEQ==", + "dev": true, + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.31.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.2.tgz", - "integrity": "sha512-w63SCQ4bIwWN/+3FxzpnWrDjQRXVEGiTt9tJTRptRXeFvdZc/wLiz3FQUwNQ2CVoRGI6KUWMNUj/pk63noUfcA==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.31.2", - "@typescript-eslint/scope-manager": "4.31.2", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.1.0", - "semver": "^7.3.5", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -246,81 +378,88 @@ } } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.31.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.2.tgz", - "integrity": "sha512-3tm2T4nyA970yQ6R3JZV9l0yilE2FedYg8dcXrTar34zC9r6JB7WyBQbpIVongKPlhEMjhQ01qkwrzWy38Bk1Q==", + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.31.2", - "@typescript-eslint/types": "4.31.2", - "@typescript-eslint/typescript-estree": "4.31.2", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/parser": { - "version": "4.31.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.31.2.tgz", - "integrity": "sha512-EcdO0E7M/sv23S/rLvenHkb58l3XhuSZzKf6DBvLgHqOYdL6YFMYVtreGFWirxaU2mS1GYDby3Lyxco7X5+Vjw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "4.31.2", - "@typescript-eslint/types": "4.31.2", - "@typescript-eslint/typescript-estree": "4.31.2", - "debug": "^4.3.1" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.31.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz", - "integrity": "sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.31.2", - "@typescript-eslint/visitor-keys": "4.31.2" + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/types": { - "version": "4.31.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.2.tgz", - "integrity": "sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -328,21 +467,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.31.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz", - "integrity": "sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.31.2", - "@typescript-eslint/visitor-keys": "4.31.2", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -354,34 +494,79 @@ } } }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.31.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz", - "integrity": "sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.31.2", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "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==", - "dev": true + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vscode/test-electron": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-1.6.2.tgz", + "integrity": "sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + }, + "engines": { + "node": ">=8.9.3" + } }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -394,6 +579,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -415,6 +601,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -427,9 +614,9 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "engines": { "node": ">=6" @@ -445,21 +632,24 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -470,28 +660,18 @@ } }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -525,12 +705,15 @@ } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bluebird": { @@ -550,12 +733,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -590,6 +774,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -634,39 +819,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/chalk/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -689,24 +841,27 @@ } }, "node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "dependencies": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "glob-parent": "~5.1.0", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { - "fsevents": "~2.3.1" + "fsevents": "~2.3.2" } }, "node_modules/cliui": { @@ -721,18 +876,21 @@ } }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "node_modules/concat-map": { @@ -752,6 +910,7 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -762,12 +921,13 @@ } }, "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -794,12 +954,13 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" @@ -810,6 +971,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -822,6 +984,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -838,28 +1001,22 @@ "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", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true, "engines": { "node": ">=6" @@ -878,57 +1035,56 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -939,6 +1095,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -947,107 +1104,96 @@ "node": ">=8.0.0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 4" + "node": ">=4.0" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "is-glob": "^4.0.3" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10.13.0" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=4" + "node": "*" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -1056,10 +1202,11 @@ } }, "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1069,6 +1216,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -1077,10 +1225,11 @@ } }, "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1090,6 +1239,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1099,6 +1249,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -1107,13 +1258,15 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1122,26 +1275,29 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -1151,6 +1307,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -1159,10 +1316,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1196,12 +1354,14 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -1209,10 +1369,27 @@ } }, "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "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", @@ -1221,9 +1398,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1250,6 +1427,39 @@ "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==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/fstream/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -1263,12 +1473,6 @@ "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", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1279,21 +1483,23 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1311,11 +1517,36 @@ "node": ">= 6" } }, + "node_modules/glob/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/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -1327,16 +1558,17 @@ } }, "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -1352,23 +1584,12 @@ "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, - "engines": { - "node": ">=4" - } + "license": "MIT" }, "node_modules/he": { "version": "1.2.0", @@ -1407,10 +1628,11 @@ } }, "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -1420,6 +1642,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1434,8 +1657,9 @@ "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -1488,10 +1712,11 @@ } }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -1504,10 +1729,21 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -1517,6 +1753,18 @@ "node": ">=8" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1529,42 +1777,77 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "node_modules/jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/leader-line": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/leader-line/-/leader-line-1.0.7.tgz", + "integrity": "sha512-PhJpQLV7XychSIuGPD0TEqR9PgRYBbrhReaOcmHFOVtTw4dWKfUMAtOb7UP7xTsoib6sFzq2giQeOUHy7LCuJQ==", + "license": "MIT" }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -1594,87 +1877,106 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "dependencies": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", + "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": "20 || >=22" } }, + "node_modules/map2object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map2object/-/map2object-1.0.0.tgz", + "integrity": "sha512-JpaZKIuEcjxjcyLSykhirzd706MIVa6agPbidZbNCifl+6MHdFZ7U0Bg8cno3PN0Z9a1A690OsvxMSjc/gc9gg==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=10" + } + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } }, "node_modules/mkdirp": { "version": "0.5.5", @@ -1689,94 +1991,55 @@ } }, "node_modules/mocha": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", - "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 14.0.0" } }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/mocha/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1791,31 +2054,13 @@ "node": ">=8" } }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=10" @@ -1825,28 +2070,25 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -1867,17 +2109,18 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -1913,11 +2156,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -1948,24 +2198,43 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -1978,6 +2247,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -1988,20 +2258,12 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2024,7 +2286,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", @@ -2057,9 +2320,9 @@ "dev": true }, "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "dependencies": { "picomatch": "^2.2.1" @@ -2068,18 +2331,6 @@ "node": ">=8.10.0" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2089,20 +2340,12 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -2112,6 +2355,7 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -2133,6 +2377,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "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/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2152,6 +2429,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -2177,13 +2455,11 @@ ] }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2192,9 +2468,9 @@ } }, "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -2211,6 +2487,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -2223,75 +2500,33 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "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, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" } }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2321,92 +2556,92 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "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": { - "ansi-regex": "^5.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.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", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/stringify-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stringify-json/-/stringify-json-2.0.0.tgz", + "integrity": "sha512-Dhi9+QD3Fb+EUQWVjVjOaa8RcJVNWTIqEkurb6DXFr7sOGIu8bRHbx1G0qGJFJ4pb2y997owHUa2C26REN8rgg==", + "license": "ISC", + "dependencies": { + "map2object": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6.5.0" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "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": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=8" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "engines": { + "node": ">=8" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "license": "MIT", + "engines": { + "node": ">=14.14" + } }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -2423,17 +2658,28 @@ "node": "*" } }, + "node_modules/ts-md5": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz", + "integrity": "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -2449,6 +2695,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -2461,6 +2708,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -2469,18 +2717,25 @@ } }, "node_modules/typescript": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", - "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, "node_modules/unzipper": { "version": "0.10.11", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", @@ -2504,6 +2759,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -2514,28 +2770,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name", - "dev": true, - "dependencies": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - }, - "engines": { - "node": ">=8.9.3" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2551,71 +2785,20 @@ "node": ">= 8" } }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/wide-align/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wide-align/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "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, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/workerpool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", - "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "node_modules/wrap-ansi": { @@ -2635,39 +2818,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "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": { - "color-convert": "^2.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2683,12 +2851,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -2708,9 +2870,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "engines": { "node": ">=10" diff --git a/package.json b/package.json index 1744834d..8acd7be4 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "publisher": "StefanWehr", "icon": "icon.png", "engines": { - "vscode": "^1.49.0" + "vscode": "^1.85.0" }, "keywords": [ "Python", @@ -39,6 +39,10 @@ { "command": "write-your-python-program.run", "title": "Run program" + }, + { + "command": "write-your-python-program.programflow-visualization", + "title": "programflow-visualization" } ], "configuration": { @@ -75,17 +79,24 @@ "watch": "tsc -watch -p ./", "test": "npm run compile && npm run lint" }, + "dependencies": { + "@types/node": "^18.11.13", + "leader-line": "^1.0.7", + "stringify-json": "^2.0.0", + "tmp": "^0.2.3", + "ts-md5": "^1.3.1" + }, "devDependencies": { - "@types/glob": "^7.1.4", "@types/mocha": "^8.2.3", - "@types/node": "^14.17.18", - "@types/vscode": "^1.49.0", - "@typescript-eslint/eslint-plugin": "^4.31.2", - "@typescript-eslint/parser": "^4.31.2", - "eslint": "^7.32.0", - "glob": "^7.2.0", - "mocha": "^8.4.0", - "typescript": "^4.4.3", - "vscode-test": "^1.6.1" + "@types/node": "^18.11.13", + "@types/tmp": "^0.2.6", + "@types/vscode": "^1.85.0", + "@typescript-eslint/eslint-plugin": "^5.30.0", + "@typescript-eslint/parser": "^5.30.0", + "@vscode/test-electron": "^1.6.1", + "eslint": "^8.18.0", + "glob": "^11.0.0", + "mocha": "^10.7.3", + "typescript": "^5.4.2" } } diff --git a/pytrace-generator/main.py b/pytrace-generator/main.py new file mode 100644 index 00000000..ec0bd75d --- /dev/null +++ b/pytrace-generator/main.py @@ -0,0 +1,453 @@ +import bdb +import copy +from dataclasses import dataclass +import inspect +import io +import json +import linecache +import math +import os +import re +import socket +import sys +import types + +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + +type_name_regex = re.compile("") +import_regex = re.compile(r"^(?:[^'\"]+\s)?import ") + +# Frame objects: +# https://docs.python.org/3/reference/datamodel.html#frame-objects + +STACK_TYPES = { + int: "int", + float: "float", + bool: "bool", + str: "str", + type(None): "none" +} +HEAP_TYPES = { + type: "type", + list: "list", + tuple: "tuple", + dict: "dict", + set: "set" +} + +def primitive_type(t): + try: + return STACK_TYPES[t] + except KeyError: + return "ref" + +def complex_type(t): + try: + return STACK_TYPES[t] + except KeyError: + try: + return HEAP_TYPES[t] + except KeyError: + return "instance" + +class HeapValue: + def __init__(self, value, value_type=None, key_lookup_table=None): + self.value = value + self.value_type = value_type + if value_type is None: + self.type_str = complex_type(type(value)) + else: + self.type_str = complex_type(value_type) + self.key_lookup_table = key_lookup_table + + def format(self): + value_type = type(self.value) + value_fmt = self.value + if value_type == list: + value_fmt = [v.format() for v in self.value] + elif value_type == dict: + value_fmt = {k: v.format() for k, v in self.value.items()} + + result = { + "type": self.type_str, + "value": value_fmt + } + + if self.key_lookup_table is not None: + key_lookup_table_fmt = {k: v.format() for k, v in self.key_lookup_table.items()} + result["keys"] = key_lookup_table_fmt + + if self.type_str == "instance": + type_name = str(self.value_type) + search_result = type_name_regex.search(type_name) + if search_result is not None: + type_name = search_result.group(1) + result["name"] = type_name + + return result + +class PrimitiveValue: + def __init__(self, value, variable_name=None): + self.variable_name = variable_name + self.type_str = primitive_type(type(value)) + if self.type_str == "ref": + self.value = id(value) + elif type(value) == float and math.isnan(value): + self.value = "NaN" # Hack because NaN could otherwise not be represented in JSON + elif type(value) == float and math.isinf(value): + # Hack because Infinity could otherwise not be represented in JSON + if value > 0: + self.value = "Infinity" + else: + self.value = "Negative Infinity" + else: + self.value = value + + def is_ref(self): + return self.type_str == "ref" + + def format(self): + d = { + "type": self.type_str, + "value": self.value + } + if self.variable_name is not None: + d["name"] = self.variable_name + return d + +class StackFrame: + def __init__(self, name): + self.name = name + self.values = [] + + def push(self, variable_name, value): + value_index = None + for idx, stack_value in enumerate(self.values): + if stack_value.variable_name == variable_name: + value_index = idx + break + + stack_value = PrimitiveValue(value, variable_name) + if value_index is not None: + self.values[value_index] = stack_value + else: + self.values.append(stack_value) + + def format(self): + return { + "frameName": self.name, + "locals": [value.format() for value in self.values] + } + +class Stack: + def __init__(self): + self.frames = [] + + def push_frame(self, frame): + self.frames.append(StackFrame(frame.f_code.co_qualname)) + + def pop_frame(self): + self.frames.pop() + + def push(self, variable_name, value): + self.frames[-1].push(variable_name, value) + + def format(self): + return [frame.format() for frame in self.frames] + + def contains(self, variable_name): + for frame in self.frames: + for var in frame.values: + if var.variable_name == variable_name: + return True + return False + +class Heap: + def __init__(self, script_path): + self.script_path = script_path + self.memory = {} + + def store(self, address, value): + # This check only works because we are taking heap snapshots + if address in self.memory: + # Prevents cycles due to cyclic references + return + + value_type = type(value) + stored_value = value + key_lookup_table = None + inner_values = [] + if value_type == list or value_type == tuple or value_type == set: + stored_value = [] + for elem in value: + prim_value = PrimitiveValue(elem) + stored_value.append(prim_value) + if prim_value.is_ref(): + inner_values.append(elem) + elif value_type == dict: + stored_value = {} + key_lookup_table = {} + for k, v in value.items(): + key_id = id(k) + + key_value = PrimitiveValue(k) + key_lookup_table[key_id] = key_value + if key_value.is_ref(): + inner_values.append(k) + + prim_value = PrimitiveValue(v) + stored_value[key_id] = prim_value + if prim_value.is_ref(): + inner_values.append(v) + elif value_type == type: + stored_value = str(value) + search_result = type_name_regex.search(stored_value) + if search_result is not None: + stored_value = f"" + elif inspect.isgenerator(value): + stored_value = {} + else: + # Assume that there are no primitive types (int, bool, ...) passed to the top level heap + # Only "real" objects are left + stored_value = {} + for field in dir(value): + try: + v = getattr(value, field) + except: + # Just ignore it in case getattr fails + continue + if should_ignore_on_heap(field, v, self.script_path): + continue + + prim_value = PrimitiveValue(v) + stored_value[field] = prim_value + if prim_value.is_ref(): + inner_values.append(v) + self.memory[address] = HeapValue(stored_value, value_type, key_lookup_table) + + # Store inner elements + for inner in inner_values: + self.store(id(inner), inner) + + def format(self): + return {k: v.format() for k, v in self.memory.items()} + +@dataclass +class TraceStep: + line: int + file_path: str + stack: Stack + heap: Heap + stdout: str + + def format(self): + return { + "line": self.line, + "filePath": self.file_path, + "stack": self.stack.format(), + "heap": self.heap.format(), + "stdout": self.stdout, + } + + +def should_ignore(variable_name, value, script_path, ignore_list = []): + if variable_name in ignore_list or variable_name.startswith("__"): + return True + if inspect.isbuiltin(value): + return True + if inspect.ismodule(value): + return True + if inspect.isframe(value): + return True + return False + +def should_ignore_on_stack(variable_name, value, script_path, ignore_list = []): + if should_ignore(variable_name, value, script_path, ignore_list): + return True + return False + +def should_ignore_on_heap(variable_name, value, script_path, ignore_list = []): + if should_ignore(variable_name, value, script_path, ignore_list): + return True + return False + + +def generate_heap(frame, script_path, ignore, return_value = None): + heap = Heap(script_path) + while True: + for variable_name in frame.f_locals: + if should_ignore_on_stack(variable_name, frame.f_locals[variable_name], script_path, ignore): + continue + if primitive_type(type(frame.f_locals[variable_name])) != "ref": + continue + value = frame.f_locals[variable_name] + heap.store(id(value), value) + + if return_value is not None: + # Store return value + if not should_ignore_on_stack("return", return_value, script_path) and not primitive_type(type(return_value)) != "ref": + heap.store(id(return_value), return_value) + + frame = frame.f_back + if frame is None or frame.f_code.co_qualname == "Bdb.run": + break + + return heap + + +class ShownClassDefs: + def __init__(self): + self.frames = [] + + def did_show(self, filename, line): + return (filename, line) in self.frames[-1] + + def append(self, filename, line): + self.frames[-1].append((filename, line)) + + def push_frame(self): + self.frames.append([]) + + def pop_frame(self): + self.frames.pop() + + +class PyTraceGenerator(bdb.Bdb): + def __init__(self, trace_socket): + super().__init__() + self.trace_socket = trace_socket + self.stack = Stack() + self.stack_ignore = [] + self.init = False + self.filename = "" + self.skip_until = None + self.import_following = False + self.last_step_was_class = False + self.prev_num_frames = 0 + self.shown_class_defs = ShownClassDefs() + self.accumulated_stdout = "" + self.captured_stdout = io.StringIO() + + def trace_dispatch(self, frame, event, arg): + filename = frame.f_code.co_filename + + # Skip built-in modules + # This might not be the best solution. Adjust if required. + skip = False + if self.skip_until is not None: + skip = filename != self.skip_until + elif not filename.startswith(os.path.dirname(self.filename)): + skip = True + self.skip_until = frame.f_back.f_code.co_filename + if skip: + return self.trace_dispatch + else: + self.skip_until = None + + line = frame.f_lineno + if not self.init: + self.init = True + for variable_name in frame.f_locals: + self.stack_ignore.append(variable_name) + elif self.import_following: + # Ignore new variables introduced through import + for variable_name in frame.f_locals: + if should_ignore_on_stack(variable_name, frame.f_locals[variable_name], self.filename, self.stack_ignore): + continue + if not self.stack.contains(variable_name): + self.stack_ignore.append(variable_name) + + # Check if the next line will be an import + next_source_line = linecache.getline(filename, line).strip() + self.import_following = import_regex.search(next_source_line) is not None + + display_return = event == "return" and len(self.stack.frames) > 1 + if event == "line" or display_return: + for variable_name in frame.f_locals: + if should_ignore_on_stack(variable_name, frame.f_locals[variable_name], self.filename, self.stack_ignore): + continue + self.stack.push(variable_name, frame.f_locals[variable_name]) + if event == "return" and display_return: + self.stack.push("return", arg) + heap = generate_heap(frame, self.filename, self.stack_ignore, return_value=arg) + else: + heap = generate_heap(frame, self.filename, self.stack_ignore) + accumulated_stdout = self.accumulated_stdout + self.captured_stdout.getvalue() + + step = TraceStep(line, filename, copy.deepcopy(self.stack), copy.deepcopy(heap), accumulated_stdout) + + is_annotation = next_source_line.startswith("@") + should_display_step = not is_annotation + is_class_def = next_source_line.startswith("class ") + class_def_already_shown = is_class_def and self.shown_class_defs.did_show(filename, line) + should_display_step = should_display_step and not class_def_already_shown + num_frames = len(self.stack.frames) + is_inside_class_def = num_frames > self.prev_num_frames and self.last_step_was_class + should_display_step = should_display_step and not is_inside_class_def + if should_display_step: + # Output trace + if self.trace_socket is not None: + json_str = json.dumps(step.format()).encode('utf-8') + json_len = len(json_str).to_bytes(4, byteorder='big', signed=False) + self.trace_socket.sendall(json_len) + self.trace_socket.sendall(json_str) + self.accumulated_stdout = accumulated_stdout + self.clear_stdout_capture() + if is_class_def: + self.shown_class_defs.append(filename, line) + self.last_step_was_class = is_class_def + self.prev_num_frames = num_frames + if event == "call": + self.stack.push_frame(frame) + self.shown_class_defs.push_frame() + elif event == "return": + self.stack.pop_frame() + self.shown_class_defs.pop_frame() + # TODO exception + + return self.trace_dispatch + + def clear_stdout_capture(self): + self.captured_stdout.close() + self.captured_stdout = io.StringIO() + sys.stdout = self.captured_stdout + + def run_script(self, filename, script_str): + self.filename = filename + code = compile(script_str, self.filename, "exec") + real_stdout = sys.stdout + sys.stdout = self.captured_stdout + self.run(code) + sys.stdout = real_stdout + + +if len(sys.argv) <= 1: + eprint("not enough arguments") + eprint("usage: python main.py file.py [port]") + exit(1) + +filename = os.path.abspath(sys.argv[1]) +with open(filename, "r") as f: + script_str = f.read() + +# Add a 'pass' at the end to also get the last trace step +# It's a bit hacky but probably the easiest solution +script_str += "\npass\n" + +# Add script directory to path +sys.path.insert(0, os.path.dirname(filename)) + +trace_socket = None +try: + if len(sys.argv) > 2: + trace_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + trace_socket.connect(("127.0.0.1", int(sys.argv[2]))) +except: + trace_socket = None + +debugger = PyTraceGenerator(trace_socket) +debugger.run_script(filename, script_str) + +if trace_socket is not None: + trace_socket.close() diff --git a/pytrace-generator/test/generateExpectation.py b/pytrace-generator/test/generateExpectation.py new file mode 100644 index 00000000..805b60ec --- /dev/null +++ b/pytrace-generator/test/generateExpectation.py @@ -0,0 +1,33 @@ +import json +import os +import socket +import subprocess +import sys + +from util import read_trace_entries + +if __name__ == '__main__': + python_file = sys.argv[1] + trace_file = f"{sys.argv[1]}.json" + trace_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + trace_socket.bind(("127.0.0.1", 0)) + trace_socket.listen(1) + port = trace_socket.getsockname()[1] + p = subprocess.Popen( + ["python3", os.path.join(os.path.dirname(os.path.dirname(__file__)), "main.py"), python_file, str(port)] + ) + connection, address = trace_socket.accept() + data = bytearray() + while True: + buf = connection.recv(4096) + if len(buf) == 0: + break + data.extend(buf) + connection.close() + trace_socket.close() + returncode = p.wait() + if returncode != 0: + raise RuntimeError("trace generator did not exit with exit code 0") + trace_entries = read_trace_entries(data) + with open(trace_file, "w") as f: + json.dump(trace_entries, f, indent="\t") diff --git a/pytrace-generator/test/runTests.py b/pytrace-generator/test/runTests.py new file mode 100644 index 00000000..6d1335d2 --- /dev/null +++ b/pytrace-generator/test/runTests.py @@ -0,0 +1,52 @@ +import json +import os +import socket +import subprocess +import unittest + +from util import read_trace_entries + +class TestTraceGeneration(unittest.TestCase): + pass + +def generate_test(python_file, expected_trace_path): + def test(self): + trace_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + trace_socket.bind(("127.0.0.1", 0)) + trace_socket.listen(1) + port = trace_socket.getsockname()[1] + p = subprocess.Popen( + ["python3", os.path.join(os.path.dirname(os.path.dirname(__file__)), "main.py"), python_file, str(port)] + ) + connection, address = trace_socket.accept() + data = bytearray() + while True: + buf = connection.recv(4096) + if len(buf) == 0: + break + data.extend(buf) + connection.close() + trace_socket.close() + returncode = p.wait() + self.assertEqual(returncode, 0) + if expected_trace_path is not None: + trace_entries = read_trace_entries(data) + with open(expected_trace_path) as f: + expected_trace = json.load(f) + self.assertEqual(trace_entries, expected_trace) + + return test + +if __name__ == '__main__': + test_cases_dir = os.path.join(os.path.dirname(__file__), "test-cases") + with os.scandir(test_cases_dir) as scan: + for entry in scan: + if not entry.is_file() or not entry.name.endswith(".py"): + continue + json_path = f"{entry.path}.json" + if not os.path.isfile(json_path): + json_path = None + test_name = f'test_{entry.name[:-3]}' + test = generate_test(entry.path, json_path) + setattr(TestTraceGeneration, test_name, test) + unittest.main() diff --git a/pytrace-generator/test/test-cases/empty.py b/pytrace-generator/test/test-cases/empty.py new file mode 100644 index 00000000..e69de29b diff --git a/pytrace-generator/test/test-cases/empty.py.json b/pytrace-generator/test/test-cases/empty.py.json new file mode 100644 index 00000000..8c5ac30e --- /dev/null +++ b/pytrace-generator/test/test-cases/empty.py.json @@ -0,0 +1,14 @@ +[ + { + "line": 2, + "filePath": "empty.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/factorial.py b/pytrace-generator/test/test-cases/factorial.py new file mode 100644 index 00000000..b3245fc0 --- /dev/null +++ b/pytrace-generator/test/test-cases/factorial.py @@ -0,0 +1,8 @@ +def factorical(n): + if n <= 1: + return 1 + prev = factorical(n - 1) + a = n * prev + return a + +res1 = factorical(2) diff --git a/pytrace-generator/test/test-cases/factorial.py.json b/pytrace-generator/test/test-cases/factorial.py.json new file mode 100644 index 00000000..7b1c40fd --- /dev/null +++ b/pytrace-generator/test/test-cases/factorial.py.json @@ -0,0 +1,404 @@ +[ + { + "line": 1, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 8, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 2, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 4, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 2, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 1, + "name": "n" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 3, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 1, + "name": "n" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 3, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 1, + "name": "n" + }, + { + "type": "int", + "value": 1, + "name": "return" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 5, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + }, + { + "type": "int", + "value": 1, + "name": "prev" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 6, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + }, + { + "type": "int", + "value": 1, + "name": "prev" + }, + { + "type": "int", + "value": 2, + "name": "a" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 6, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + } + ] + }, + { + "frameName": "factorical", + "locals": [ + { + "type": "int", + "value": 2, + "name": "n" + }, + { + "type": "int", + "value": 1, + "name": "prev" + }, + { + "type": "int", + "value": 2, + "name": "a" + }, + { + "type": "int", + "value": 2, + "name": "return" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 10, + "filePath": "factorial.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "factorical" + }, + { + "type": "int", + "value": 2, + "name": "res1" + } + ] + } + ], + "heap": { + "0": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/generatorObject.py b/pytrace-generator/test/test-cases/generatorObject.py new file mode 100644 index 00000000..1a51203e --- /dev/null +++ b/pytrace-generator/test/test-cases/generatorObject.py @@ -0,0 +1 @@ +g = (i for i in [1, 2]) \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/importArgparse.py b/pytrace-generator/test/test-cases/importArgparse.py new file mode 100644 index 00000000..1b647525 --- /dev/null +++ b/pytrace-generator/test/test-cases/importArgparse.py @@ -0,0 +1 @@ +import argparse diff --git a/pytrace-generator/test/test-cases/importArgparse.py.json b/pytrace-generator/test/test-cases/importArgparse.py.json new file mode 100644 index 00000000..ba9d8d2b --- /dev/null +++ b/pytrace-generator/test/test-cases/importArgparse.py.json @@ -0,0 +1,26 @@ +[ + { + "line": 1, + "filePath": "importArgparse.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 3, + "filePath": "importArgparse.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/importShutil.py b/pytrace-generator/test/test-cases/importShutil.py new file mode 100644 index 00000000..d7b1da23 --- /dev/null +++ b/pytrace-generator/test/test-cases/importShutil.py @@ -0,0 +1 @@ +import shutil diff --git a/pytrace-generator/test/test-cases/importShutil.py.json b/pytrace-generator/test/test-cases/importShutil.py.json new file mode 100644 index 00000000..e6a09559 --- /dev/null +++ b/pytrace-generator/test/test-cases/importShutil.py.json @@ -0,0 +1,26 @@ +[ + { + "line": 1, + "filePath": "importShutil.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 3, + "filePath": "importShutil.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/importSubprocess.py b/pytrace-generator/test/test-cases/importSubprocess.py new file mode 100644 index 00000000..2933cb5d --- /dev/null +++ b/pytrace-generator/test/test-cases/importSubprocess.py @@ -0,0 +1 @@ +import subprocess diff --git a/pytrace-generator/test/test-cases/importSubprocess.py.json b/pytrace-generator/test/test-cases/importSubprocess.py.json new file mode 100644 index 00000000..d650433f --- /dev/null +++ b/pytrace-generator/test/test-cases/importSubprocess.py.json @@ -0,0 +1,26 @@ +[ + { + "line": 1, + "filePath": "importSubprocess.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 3, + "filePath": "importSubprocess.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/importTime.py b/pytrace-generator/test/test-cases/importTime.py new file mode 100644 index 00000000..6693bcc0 --- /dev/null +++ b/pytrace-generator/test/test-cases/importTime.py @@ -0,0 +1 @@ +import time \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/importTime.py.json b/pytrace-generator/test/test-cases/importTime.py.json new file mode 100644 index 00000000..e9102f0b --- /dev/null +++ b/pytrace-generator/test/test-cases/importTime.py.json @@ -0,0 +1,26 @@ +[ + { + "line": 1, + "filePath": "importTime.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 2, + "filePath": "importTime.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/importWypp.py b/pytrace-generator/test/test-cases/importWypp.py new file mode 100644 index 00000000..b0957632 --- /dev/null +++ b/pytrace-generator/test/test-cases/importWypp.py @@ -0,0 +1 @@ +from wypp import * \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/importWypp.py.json b/pytrace-generator/test/test-cases/importWypp.py.json new file mode 100644 index 00000000..78720365 --- /dev/null +++ b/pytrace-generator/test/test-cases/importWypp.py.json @@ -0,0 +1,26 @@ +[ + { + "line": 1, + "filePath": "importWypp.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 2, + "filePath": "importWypp.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/test-cases/module1.py b/pytrace-generator/test/test-cases/module1.py new file mode 100644 index 00000000..6acd97b8 --- /dev/null +++ b/pytrace-generator/test/test-cases/module1.py @@ -0,0 +1,3 @@ +# This test ensures that module2 can be imported and used +import module2 +b = module2.myfun(1) diff --git a/pytrace-generator/test/test-cases/module2.py b/pytrace-generator/test/test-cases/module2.py new file mode 100644 index 00000000..67670c9e --- /dev/null +++ b/pytrace-generator/test/test-cases/module2.py @@ -0,0 +1,5 @@ +def myfun(i): + i += 1 + i += 1 + i += 1 + return i diff --git a/pytrace-generator/test/test-cases/wyppSimple.py b/pytrace-generator/test/test-cases/wyppSimple.py new file mode 100644 index 00000000..8f2e9820 --- /dev/null +++ b/pytrace-generator/test/test-cases/wyppSimple.py @@ -0,0 +1,16 @@ +from __future__ import annotations +from wypp import * + +@record +class Bar: + baz: str + +def generate_bar(): + return Bar("baz value") + +obj1 = Bar("baz value") +print(obj1.baz) +obj2 = generate_bar() +print(obj2.baz) + +check(obj1, obj2) diff --git a/pytrace-generator/test/test-cases/wyppSimple.py.json b/pytrace-generator/test/test-cases/wyppSimple.py.json new file mode 100644 index 00000000..fdafe8c1 --- /dev/null +++ b/pytrace-generator/test/test-cases/wyppSimple.py.json @@ -0,0 +1,499 @@ +[ + { + "line": 1, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 2, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 5, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [] + } + ], + "heap": {}, + "stdout": "" + }, + { + "line": 8, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + } + }, + "stdout": "" + }, + { + "line": 11, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + } + }, + "stdout": "" + }, + { + "line": 12, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + }, + { + "type": "ref", + "value": 2, + "name": "obj1" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + }, + "2": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + } + }, + "stdout": "" + }, + { + "line": 13, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + }, + { + "type": "ref", + "value": 2, + "name": "obj1" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + }, + "2": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + } + }, + "stdout": "baz value\n" + }, + { + "line": 9, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + }, + { + "type": "ref", + "value": 2, + "name": "obj1" + } + ] + }, + { + "frameName": "generate_bar", + "locals": [] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + }, + "2": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + } + }, + "stdout": "baz value\n" + }, + { + "line": 9, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + }, + { + "type": "ref", + "value": 2, + "name": "obj1" + } + ] + }, + { + "frameName": "generate_bar", + "locals": [ + { + "type": "ref", + "value": 3, + "name": "return" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + }, + "2": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + }, + "3": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + } + }, + "stdout": "baz value\n" + }, + { + "line": 14, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + }, + { + "type": "ref", + "value": 2, + "name": "obj1" + }, + { + "type": "ref", + "value": 3, + "name": "obj2" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + }, + "2": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + }, + "3": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + } + }, + "stdout": "baz value\n" + }, + { + "line": 16, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + }, + { + "type": "ref", + "value": 2, + "name": "obj1" + }, + { + "type": "ref", + "value": 3, + "name": "obj2" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + }, + "2": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + }, + "3": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + } + }, + "stdout": "baz value\nbaz value\n" + }, + { + "line": 18, + "filePath": "wyppSimple.py", + "stack": [ + { + "frameName": "", + "locals": [ + { + "type": "ref", + "value": 0, + "name": "Bar" + }, + { + "type": "ref", + "value": 1, + "name": "generate_bar" + }, + { + "type": "ref", + "value": 2, + "name": "obj1" + }, + { + "type": "ref", + "value": 3, + "name": "obj2" + } + ] + } + ], + "heap": { + "0": { + "type": "type", + "value": "" + }, + "1": { + "type": "instance", + "value": {}, + "name": "function" + }, + "2": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + }, + "3": { + "type": "instance", + "value": { + "baz": { + "type": "str", + "value": "baz value" + } + }, + "name": "Bar" + } + }, + "stdout": "baz value\nbaz value\n" + } +] \ No newline at end of file diff --git a/pytrace-generator/test/util.py b/pytrace-generator/test/util.py new file mode 100644 index 00000000..5e288ccc --- /dev/null +++ b/pytrace-generator/test/util.py @@ -0,0 +1,38 @@ +import json + +def read_trace_entries(data): + entries = [] + while len(data) > 0: + entry_len = int.from_bytes(data[:4], byteorder="big", signed=False) + data = data[4:] + entry = json.loads(str(data[:entry_len], encoding="utf-8")) + test_cases_str = "test-cases/" + idx = entry["filePath"].rfind(test_cases_str) + if idx >= 0: + # Remove user specific path stuff to allow for equality testing + entry["filePath"] = entry["filePath"][idx + len(test_cases_str):] + normalize_refs(entry) + entries.append(entry) + data = data[entry_len:] + return entries + +def normalize_refs(entry): + next_id = 0 + mapping = {} + for frame in entry["stack"]: + for var in frame["locals"]: + if var["type"] == "ref": + original_id = var["value"] + if original_id in mapping: + var["value"] = mapping[original_id] + else: + var["value"] = next_id + mapping[original_id] = next_id + if str(next_id) in entry["heap"]: + tmp = entry["heap"][str(next_id)] + entry["heap"][str(next_id)] = entry["heap"][str(original_id)] + entry["heap"][str(original_id)] = tmp + else: + entry["heap"][str(next_id)] = entry["heap"][str(original_id)] + del entry["heap"][str(original_id)] + next_id += 1 diff --git a/src/extension.ts b/src/extension.ts index 18e86f98..fa2ce9f1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,6 +6,9 @@ import * as fs from 'fs'; import * as path from 'path'; import { Uri } from 'vscode'; +import { getProgFlowVizCallback } from './programflow-visualization/main'; +import { initTraceCache } from './programflow-visualization/trace_cache'; + const extensionId = 'write-your-python-program'; const python3ConfigKey = 'python3Cmd'; const verboseConfigKey = 'verbose'; @@ -126,6 +129,15 @@ function installCmd( installButton(buttonTitle, cmdId); } +function initProgramFlowVisualization(context: vscode.ExtensionContext, outChannel: vscode.OutputChannel) { + initTraceCache(context); + const cmdId = extensionId + ".programflow-visualization"; + let disposable = vscode.commands.registerCommand(cmdId, getProgFlowVizCallback(context, outChannel)); + disposables.push(disposable); + context.subscriptions.push(disposable); + installButton("$(debug-alt-small) Visualize", cmdId); +} + type PythonCmdResult = { kind: "success", cmd: string[] } | { @@ -134,7 +146,7 @@ type PythonCmdResult = { kind: "warning", msg: string, cmd: string[] }; -function getPythonCmd(ext: PythonExtension): PythonCmdResult { +export function getPythonCmd(ext: PythonExtension): PythonCmdResult { const config = vscode.workspace.getConfiguration(extensionId); const hasConfig = config && config[python3ConfigKey]; if (hasConfig) { @@ -302,7 +314,7 @@ class TerminalLinkProvider implements vscode.TerminalLinkProvider { } } -class PythonExtension { +export class PythonExtension { private pyApi: any; constructor() { @@ -322,6 +334,9 @@ export function activate(context: vscode.ExtensionContext) { console.log('Activating extension ' + extensionId); + const outChannel = vscode.window.createOutputChannel("Write Your Python Program"); + disposables.push(outChannel); + fixPythonConfig(context); const terminals: { [name: string]: TerminalContext } = {}; @@ -383,6 +398,8 @@ export function activate(context: vscode.ExtensionContext) { } ); + initProgramFlowVisualization(context, outChannel); + vscode.window.onDidChangeActiveTextEditor(showHideButtons); showHideButtons(vscode.window.activeTextEditor); diff --git a/src/programflow-visualization/FileHandler.ts b/src/programflow-visualization/FileHandler.ts new file mode 100644 index 00000000..90b0b7c3 --- /dev/null +++ b/src/programflow-visualization/FileHandler.ts @@ -0,0 +1,38 @@ +import stringify from 'stringify-json'; +import * as vscode from 'vscode'; +import util = require('util'); +import path = require('path'); + +export async function getContentOf(fileUri: vscode.Uri): Promise { + return new util.TextDecoder('utf-8').decode(await vscode.workspace.fs.readFile(fileUri)); +} + +export async function deleteFile(file: vscode.Uri) { + await vscode.workspace.fs.delete(file); +} + +export async function duplicateFileAndExtendWithPass( + file: vscode.Uri, + fileContent: string +): Promise { + const fileName = path.basename(file.fsPath).split('.')[0]; + + const tempFileUri = vscode.Uri.file(file.fsPath.replace(`/${fileName}.`, `/${fileName}_debug.`)); + const utf8Content = new util.TextEncoder().encode(fileContent.concat('\npass')); + + await vscode.workspace.fs.writeFile(tempFileUri, utf8Content); + + return tempFileUri; +} + +export async function createBackendTraceOutput(backendTrace: BackendTrace, file: vscode.Uri) { + const fileName = path.basename(file.fsPath).split('.')[0]; + await vscode.workspace.fs.writeFile( + vscode.Uri.parse(file.fsPath.replace(path.basename(file.fsPath), `backend_trace_${fileName}.json`)), + new util.TextEncoder().encode(stringify(backendTrace)) + ); +} + +export async function writeBackendTrace(backendTrace: BackendTrace, path: string) { + await vscode.workspace.fs.writeFile(vscode.Uri.file(path), new util.TextEncoder().encode(stringify(backendTrace))); +} diff --git a/src/programflow-visualization/backend/backend.ts b/src/programflow-visualization/backend/backend.ts new file mode 100644 index 00000000..cdba9bd5 --- /dev/null +++ b/src/programflow-visualization/backend/backend.ts @@ -0,0 +1,41 @@ +import { ExtensionContext, OutputChannel, Uri } from 'vscode'; +import { MessagePort, Worker } from 'worker_threads'; +import { PythonExtension, getPythonCmd } from '../../extension'; +import path = require('path'); + +export function startBackend(context: ExtensionContext, file: Uri, outChannel: OutputChannel): MessagePort { + const pyExt = new PythonExtension(); + const pythonCmdResult = getPythonCmd(pyExt); + let pythonCmd = ["python3"]; + switch (pythonCmdResult.kind) { + case "error": + outChannel.appendLine(`Getting Python command failed: ${pythonCmdResult.msg}`); + break; + case "warning": + outChannel.appendLine(`Warning while getting Python command: ${pythonCmdResult.msg}`); + pythonCmd = pythonCmdResult.cmd; + break; + case "success": + pythonCmd = pythonCmdResult.cmd; + break; + } + + // Get WYPP path + const runYourProgramPath = context.asAbsolutePath("python/src/runYourProgram.py"); + + const mainPath = context.asAbsolutePath("pytrace-generator/main.py"); + const workerPath = path.resolve(__dirname, 'trace_generator.js'); + const worker = new Worker(workerPath); + const traceChannel = new MessageChannel(); + const logChannel = new MessageChannel(); + logChannel.port2.on('message', async (logEntry) => outChannel.append(logEntry)); + worker.postMessage({ + file: file.fsPath, + mainPath: mainPath, + logPort: logChannel.port1, + pythonCmd: pythonCmd, + runYourProgramPath: runYourProgramPath, + tracePort: traceChannel.port1 + }, [logChannel.port1, traceChannel.port1]); + return traceChannel.port2; +} diff --git a/src/programflow-visualization/backend/trace_generator.ts b/src/programflow-visualization/backend/trace_generator.ts new file mode 100644 index 00000000..5fae4985 --- /dev/null +++ b/src/programflow-visualization/backend/trace_generator.ts @@ -0,0 +1,98 @@ +import { ChildProcessWithoutNullStreams, execFile, ExecFileException, spawn } from 'child_process'; +import { AddressInfo, createServer } from 'net'; +import { dirname } from 'path'; +import { MessagePort, isMainThread, parentPort } from 'worker_threads'; + +function installWypp(pythonCmd: string[], runYourProgramPath: string, callback: (error: ExecFileException | null, stdout: string, stderr: string) => void) { + const args = pythonCmd.slice(1).concat([runYourProgramPath, '--install-mode', 'installOnly']); + execFile(pythonCmd[0], args, { windowsHide: true }, callback); +} + +export function generateTrace(pythonCmd: string[], mainPath: string, filePath: string, tracePort: MessagePort, logPort: MessagePort) { + let childRef: ChildProcessWithoutNullStreams[] = []; + let buffer = Buffer.alloc(0); + const server = createServer((socket) => { + socket.on('data', (data) => { + buffer = Buffer.concat([buffer, data]); + while (buffer.length >= 4) { + const dataLen = buffer.readUint32BE(0); + if (buffer.length >= 4 + dataLen) { + const traceStr = buffer.subarray(4, 4 + dataLen).toString(); + try { + const traceElem = JSON.parse(traceStr); + tracePort.postMessage(traceElem); + buffer = buffer.subarray(4 + dataLen); + } catch (error) { + logPort.postMessage(`JSON parsing of trace element failed: ${error}\n`); + tracePort.close(); + if (childRef.length > 0) { + childRef[0].kill(); + } + } + } else { + break; + } + } + }); + + socket.on('end', () => { + tracePort.close(); + }); + }); + server.listen(0, '127.0.0.1', () => { + const port = (server.address() as AddressInfo)?.port; + const traceArgs = [mainPath, filePath, port.toString()]; + const args = pythonCmd.slice(1).concat(traceArgs); + const child = spawn(pythonCmd[0], args, { cwd: dirname(filePath), windowsHide: true }); + childRef.push(child); + let err = ""; + + tracePort.on('close', () => { + child.kill(); + logPort.close(); + }); + + child.stdout.on('data', (data) => { + logPort.postMessage(data.toString()); + }); + child.stderr.on('data', (data) => { + logPort.postMessage(data.toString()); + }); + child.on('close', (code) => { + if (code !== 0) { + logPort.postMessage(`trace generator failed with code ${code}: ${err}\n`); + } + }); + child.on('error', (error) => { + logPort.postMessage(`${error}\n`); + logPort.close(); + tracePort.close(); + }); + }); +} + +if (!isMainThread && parentPort) { + parentPort.once('message', (initParams) => { + if (initParams.pythonCmd.length === 0) { + initParams.logPort.postMessage('Python command is missing\n'); + initParams.logPort.close(); + initParams.tracePort.close(); + return; + } + installWypp(initParams.pythonCmd, initParams.runYourProgramPath, (error, stdout, stderr) => { + if (stdout.length > 0) { + initParams.logPort.postMessage(`${stdout}\n`); + } + if (stderr.length > 0) { + initParams.logPort.postMessage(`${stderr}\n`); + } + if (error !== null) { + initParams.logPort.postMessage(`${error}\n`); + initParams.logPort.close(); + initParams.tracePort.close(); + return; + } + generateTrace(initParams.pythonCmd, initParams.mainPath, initParams.file, initParams.tracePort, initParams.logPort); + }); + }); +} diff --git a/src/programflow-visualization/constants.ts b/src/programflow-visualization/constants.ts new file mode 100644 index 00000000..96d36c1d --- /dev/null +++ b/src/programflow-visualization/constants.ts @@ -0,0 +1,11 @@ +import * as vscode from 'vscode'; + +export namespace Variables { + export const CACHED_TRACES = 'programflow-visualization.cached-traces'; + export const TRACE_CACHE_DIR = 'programflow-visualization.trace-cache-dir'; +} + +export const nextLineExecuteHighlightType = vscode.window.createTextEditorDecorationType({ + backgroundColor: 'rgba(255, 255, 0, 0.25)', // Yellow + isWholeLine: true, +}); diff --git a/src/programflow-visualization/frontend/HTMLGenerator.ts b/src/programflow-visualization/frontend/HTMLGenerator.ts new file mode 100644 index 00000000..28c4c1f7 --- /dev/null +++ b/src/programflow-visualization/frontend/HTMLGenerator.ts @@ -0,0 +1,214 @@ +function escapeHTML(s: any) { + if (s !== undefined && s !== null) { + return s.toString().replace(/[^0-9A-Za-z ]/g, (c: string) => "&#" + c.charCodeAt(0) + ";"); + } else { + return s; + } +} + +function toID(s: any) { + if (s !== undefined && s !== null) { + return Array.from(s.toString()).filter((c) => { + return c !== "\"" && c !== "\t" && c !== "\n" && c !== "\f" && c !== "\r" && c !== " "; + }).join(""); + } else { + return s; + } +} + +function keyToString(key: any) { + if (key.type !== undefined) { + return key.type === 'ref' ? '' : (key.value ? key.value : key); + } else { + return key.toString(); + } +} + +export class HTMLGenerator { + uniqueId: number = -1; + + constructor() { + } + + generateHTML(traceElement: BackendTraceElem): FrontendTraceElem { + this.uniqueId = -1; + + const frameItems = ` +
+ ${traceElement.stack.map((stackElem, index) => this.frameItem(index, stackElem)).join('')} +
+ `; + + const keys = Array.from(Object.keys(traceElement.heap)); + const values = Array.from(Object.values(traceElement.heap)); + const objectItems = ` +
+ ${keys.map((name, index) => this.objectItem(name, values[index])).join('')} +
+ `; + return [traceElement.line, frameItems, objectItems, traceElement.filePath, traceElement.stdout]; + } + + private objectItem(name: string, value: HeapValue): string { + let headline: string; + switch (value.type) { + case 'instance': + headline = value.name; + break; + case 'type': + // Types are displayed in the same way as function objects. + // This is simply done for consistency, even if it's not quite correct. + headline = value.value; + break; + default: + headline = value.type; + } + + return ` +
+
${escapeHTML(headline)}
+
${this.heapValue(name, value)}
+
+ `; + } + + private heapValue(name: string, heapValue: HeapValue): string { + let result = ''; + let keyLen = 0; + switch (heapValue.type) { + case 'dict': + const metaKeys = Array.from(Object.keys(heapValue.keys)); + // keys and value are not really Maps but rather objects + // -> Conversion required + const keyMap = new Map(Object.entries(heapValue.keys)); + const valueMap = new Map(Object.entries(heapValue.value)); + keyLen = 0; + metaKeys.forEach(metaKey => { + let key = keyMap.get(metaKey)!; + keyLen = Math.max(keyToString(key).length, keyLen); + }); + result = ` +
+ ${metaKeys.map(metaKey => this.dictValue(keyLen, keyMap.get(metaKey)!, valueMap.get(metaKey)!)).join('')} +
+ `; + break; + case 'instance': + const instanceKeys = Array.from(Object.keys(heapValue.value)); + const instanceValues = Array.from(Object.values(heapValue.value)); // maybe endpointer look for if its exist and if add a second number or key or smth + keyLen = 0; + instanceKeys.forEach(key => { + keyLen = Math.max(keyToString(key).length, keyLen); + }); + result = ` +
+ ${instanceKeys.map((key, index) => this.dictValue(keyLen, key, instanceValues[index])).join('')} +
+ `; + break; + case 'set': + result = ` +
+ ${heapValue.value.map((v, i) => this.setValue(v)).join('')} +
+ `; + break; + case 'type': + result = ` +
+
+ `; + break; + /* tuple, list, int[], int[][], ...*/ + default: + result = ` +
+ ${heapValue.value.map((v, i) => this.listValue(v, i)).join('')} +
+ `; + break; + } + return result; + } + + private dictValue(maxKeyLen: number, key: any, value: Value): string { + this.uniqueId++; + const keyWidth = Math.min(100, maxKeyLen * 10 + 10); + const valWidth = 200 - keyWidth; + return ` +
+
+ ${escapeHTML(keyToString(key))} +
+
+ ${value.type === 'ref' ? '' : this.getCorrectValueOf(value)} +
+
+ `; + } + + private listValue(value: Value, index: number): string { + this.uniqueId++; + return ` +
+
+ ${index} +
+
+ ${value.type === 'ref' ? '' : this.getCorrectValueOf(value)} +
+
+ `; + } + + private setValue(value: Value): string { + this.uniqueId++; + return ` +
+
+ ${value.type === 'ref' ? '' : this.getCorrectValueOf(value)} +
+
+ `; + } + + private frameItem(index: number, stackElem: StackElem): string { + return ` +
+
+ ${stackElem.frameName === '' ? 'Global' : escapeHTML(stackElem.frameName)} +
+
+ ${stackElem.locals.map(namedValue => this.frameSubItem(stackElem.frameName, namedValue)).join('')} +
+
+ `; + } + + private frameSubItem(frameName: string, namedValue: NamedValue): string { + const isReturn = namedValue.name === 'return'; + return ` +
+
+ ${escapeHTML(namedValue.name)} +
+
+ ${this.getCorrectValueOf(namedValue)} +
+
+ `; + } + + private getCorrectValueOf(value: Value): string { + switch (value.type) { + case 'ref': + return ''; + case 'none': + return 'None'; + default: + return escapeHTML(`${value.value}`); + } + } +} diff --git a/src/programflow-visualization/frontend/frontend.ts b/src/programflow-visualization/frontend/frontend.ts new file mode 100644 index 00000000..3a73b686 --- /dev/null +++ b/src/programflow-visualization/frontend/frontend.ts @@ -0,0 +1,24 @@ +import { ExtensionContext } from 'vscode'; +import { VisualizationPanel } from './visualization_panel'; +import { MessagePort } from 'worker_threads'; +import * as TraceCache from '../trace_cache'; + +export async function startFrontend( + context: ExtensionContext, + filePath: string, + fileHash: string, + tracePort: MessagePort | null): Promise { + var trace: BackendTrace = []; + if (await TraceCache.traceAlreadyExists(context, fileHash)) { + trace = await TraceCache.getTrace(context, fileHash); + } + + const panel = await VisualizationPanel.getVisualizationPanel(context, filePath, fileHash, trace, tracePort); + if (!panel) { + return failure("Frontend couldn't be initialized!"); + } +} + +function failure(errorMessage: string): Failure { + return { errorMessage: errorMessage } as Failure; +} diff --git a/src/programflow-visualization/frontend/resources/leader-line.min.js b/src/programflow-visualization/frontend/resources/leader-line.min.js new file mode 100644 index 00000000..b3f2430b --- /dev/null +++ b/src/programflow-visualization/frontend/resources/leader-line.min.js @@ -0,0 +1,2 @@ +/*! LeaderLine v1.0.7 (c) anseki https://anseki.github.io/leader-line/ */ +var LeaderLine=function(){"use strict";var Z,w,O,M,I,o,t,s,h,u,n,a,e,_,v,l,r,i,E,x,p,c,d,C="leader-line",b=1,k=2,L=3,A=4,V={top:b,right:k,bottom:L,left:A},P=1,N=2,T=3,W=4,B=5,R={straight:P,arc:N,fluid:T,magnet:W,grid:B},Y="behind",f=C+"-defs",y='',X={disc:{elmId:"leader-line-disc",noRotate:!0,bBox:{left:-5,top:-5,width:10,height:10,right:5,bottom:5},widthR:2.5,heightR:2.5,bCircle:5,sideLen:5,backLen:5,overhead:0,outlineBase:1,outlineMax:4},square:{elmId:"leader-line-square",noRotate:!0,bBox:{left:-5,top:-5,width:10,height:10,right:5,bottom:5},widthR:2.5,heightR:2.5,bCircle:5,sideLen:5,backLen:5,overhead:0,outlineBase:1,outlineMax:4},arrow1:{elmId:"leader-line-arrow1",bBox:{left:-8,top:-8,width:16,height:16,right:8,bottom:8},widthR:4,heightR:4,bCircle:8,sideLen:8,backLen:8,overhead:8,outlineBase:2,outlineMax:1.5},arrow2:{elmId:"leader-line-arrow2",bBox:{left:-7,top:-8,width:11,height:16,right:4,bottom:8},widthR:2.75,heightR:4,bCircle:8,sideLen:8,backLen:7,overhead:4,outlineBase:1,outlineMax:1.75},arrow3:{elmId:"leader-line-arrow3",bBox:{left:-4,top:-5,width:12,height:10,right:8,bottom:5},widthR:3,heightR:2.5,bCircle:8,sideLen:5,backLen:4,overhead:8,outlineBase:1,outlineMax:2.5},hand:{elmId:"leader-line-hand",bBox:{left:-3,top:-12,width:40,height:24,right:37,bottom:12},widthR:10,heightR:6,bCircle:37,sideLen:12,backLen:3,overhead:37},crosshair:{elmId:"leader-line-crosshair",noRotate:!0,bBox:{left:-96,top:-96,width:192,height:192,right:96,bottom:96},widthR:48,heightR:48,bCircle:96,sideLen:96,backLen:96,overhead:0}},F={behind:Y,disc:"disc",square:"square",arrow1:"arrow1",arrow2:"arrow2",arrow3:"arrow3",hand:"hand",crosshair:"crosshair"},q={disc:"disc",square:"square",arrow1:"arrow1",arrow2:"arrow2",arrow3:"arrow3",hand:"hand",crosshair:"crosshair"},G=[b,k,L,A],D="auto",Q={x:"left",y:"top",width:"width",height:"height"},z=80,j=4,H=5,U=120,K=8,J=3.75,$=10,ee=30,te=.5522847,ne=.25*Math.PI,m=/^\s*(\-?[\d\.]+)\s*(\%)?\s*$/,ae="http://www.w3.org/2000/svg",S="-ms-scroll-limit"in document.documentElement.style&&"-ms-ime-align"in document.documentElement.style&&!window.navigator.msPointerEnabled,ie=!S&&!!document.uniqueID,oe="MozAppearance"in document.documentElement.style,le=!(S||oe||!window.chrome||!window.CSS),re=!S&&!ie&&!oe&&!le&&!window.chrome&&"WebkitAppearance"in document.documentElement.style,se=ie||S?.2:.1,ue={path:T,lineColor:"coral",lineSize:4,plugSE:[Y,"arrow1"],plugSizeSE:[1,1],lineOutlineEnabled:!1,lineOutlineColor:"indianred",lineOutlineSize:.25,plugOutlineEnabledSE:[!1,!1],plugOutlineSizeSE:[1,1]},he=(p={}.toString,c={}.hasOwnProperty.toString,d=c.call(Object),function(e){return e&&"[object Object]"===p.call(e)&&(!(e=Object.getPrototypeOf(e))||(e=e.hasOwnProperty("constructor")&&e.constructor)&&"function"==typeof e&&c.call(e)===d)}),pe=Number.isFinite||function(e){return"number"==typeof e&&window.isFinite(e)},g=(_={ease:[.25,.1,.25,1],linear:[0,0,1,1],"ease-in":[.42,0,1,1],"ease-out":[0,0,.58,1],"ease-in-out":[.42,0,.58,1]},v=1e3/60/2,l=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||function(e){setTimeout(e,v)},r=window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame||function(e){clearTimeout(e)},i=Number.isFinite||function(e){return"number"==typeof e&&window.isFinite(e)},E=[],x=0,{add:function(n,e,t,a,i,o,l){var r,s,u,h,p,c,d,f,y,m,S=++x;function g(e,t){return{value:n(t),timeRatio:e,outputRatio:t}}if("string"==typeof i&&(i=_[i]),n=n||function(){},t=this._endIndex||this._string[this._currentIndex]<"0"||"9"=this._endIndex||this._string[this._currentIndex]<"0"||"9"=this._endIndex)return null;var e=null,t=this._string[this._currentIndex];if(this._currentIndex+=1,"0"===t)e=0;else{if("1"!==t)return null;e=1}return this._skipOptionalSpacesOrDelimiter(),e}};function n(e){if(!e||0===e.length)return[];var t=new i(e),n=[];if(t.initialCommandIsMoveTo())for(;t.hasMoreData();){var a=t.parseSegment();if(null===a)break;n.push(a)}return n}function l(e){return e.map(function(e){return{type:e.type,values:Array.prototype.slice.call(e.values)}})}function r(e){var u=[],h=null,p=null,c=null,d=null,f=null,y=null,m=null;return e.forEach(function(e){var t,n,a,i,o,l,r,s;"M"===e.type?(r=e.values[0],s=e.values[1],u.push({type:"M",values:[r,s]}),d=y=r,f=m=s):"C"===e.type?(o=e.values[0],l=e.values[1],t=e.values[2],n=e.values[3],r=e.values[4],s=e.values[5],u.push({type:"C",values:[o,l,t,n,r,s]}),p=t,c=n,d=r,f=s):"L"===e.type?(r=e.values[0],s=e.values[1],u.push({type:"L",values:[r,s]}),d=r,f=s):"H"===e.type?(r=e.values[0],u.push({type:"L",values:[r,f]}),d=r):"V"===e.type?(s=e.values[0],u.push({type:"L",values:[d,s]}),f=s):"S"===e.type?(t=e.values[0],n=e.values[1],r=e.values[2],s=e.values[3],i="C"===h||"S"===h?(a=d+(d-p),f+(f-c)):(a=d,f),u.push({type:"C",values:[a,i,t,n,r,s]}),p=t,c=n,d=r,f=s):"T"===e.type?(r=e.values[0],s=e.values[1],l="Q"===h||"T"===h?(o=d+(d-p),f+(f-c)):(o=d,f),u.push({type:"C",values:[a=d+2*(o-d)/3,i=f+2*(l-f)/3,r+2*(o-r)/3,s+2*(l-s)/3,r,s]}),p=o,c=l,d=r,f=s):"Q"===e.type?(o=e.values[0],l=e.values[1],r=e.values[2],s=e.values[3],u.push({type:"C",values:[a=d+2*(o-d)/3,i=f+2*(l-f)/3,r+2*(o-r)/3,s+2*(l-s)/3,r,s]}),p=o,c=l,d=r,f=s):"A"===e.type?(n=e.values[0],a=e.values[1],i=e.values[2],o=e.values[3],l=e.values[4],r=e.values[5],s=e.values[6],0===n||0===a?(u.push({type:"C",values:[d,f,r,s,r,s]}),d=r,f=s):d===r&&f===s||b(d,f,r,s,n,a,i,o,l).forEach(function(e){u.push({type:"C",values:e}),d=r,f=s})):"Z"===e.type&&(u.push(e),d=y,f=m),h=e.type}),u}var s=e.SVGPathElement.prototype.setAttribute,u=e.SVGPathElement.prototype.removeAttribute,d=e.Symbol?e.Symbol():"__cachedPathData",f=e.Symbol?e.Symbol():"__cachedNormalizedPathData",b=function(e,t,n,a,i,o,l,r,s,u){function h(e,t,n){return{x:e*Math.cos(n)-t*Math.sin(n),y:e*Math.sin(n)+t*Math.cos(n)}}var p=Math.PI*l/180,c=[];u?(_=u[0],v=u[1],S=u[2],g=u[3]):(e=(m=h(e,t,-p)).x,t=m.y,1<(m=(y=(e-(n=(f=h(n,a,-p)).x))/2)*y/(i*i)+(d=(t-(a=f.y))/2)*d/(o*o))&&(i*=m=Math.sqrt(m),o*=m),f=i*i,m=o*o,S=(f=(r===s?-1:1)*Math.sqrt(Math.abs((f*m-f*d*d-m*y*y)/(f*d*d+m*y*y))))*i*d/o+(e+n)/2,g=f*-o*y/i+(t+a)/2,_=Math.asin(parseFloat(((t-g)/o).toFixed(9))),v=Math.asin(parseFloat(((a-g)/o).toFixed(9))),e120*Math.PI/180&&(d=v,f=n,y=a,v=s&&_=e.duration&&e.count&&e.loopsLeft<=1)return a=e.frames[e.lastFrame=e.reverse?0:e.frames.length-1],e.frameCallback(a.value,!0,a.timeRatio,a.outputRatio),void(e.framesStart=null);if(t>e.duration){if(n=Math.floor(t/e.duration),e.count){if(n>=e.loopsLeft)return a=e.frames[e.lastFrame=e.reverse?0:e.frames.length-1],e.frameCallback(a.value,!0,a.timeRatio,a.outputRatio),void(e.framesStart=null);e.loopsLeft-=n}e.framesStart+=e.duration*n,t=i-e.framesStart}e.reverse&&(t=e.duration-t),a=e.frames[e.lastFrame=Math.round(t/v)],!1!==e.frameCallback(a.value,!1,a.timeRatio,a.outputRatio)?o=!0:e.framesStart=null}}),o&&(e=l.call(window,xe))}function be(e,t){e.framesStart=Date.now(),null!=t&&(e.framesStart-=e.duration*(e.reverse?1-t:t)),e.loopsLeft=e.count,e.lastFrame=null,xe()}function ke(t,n){var e,a;return typeof t!=typeof n||(e=he(t)?"obj":Array.isArray(t)?"array":"")!=(he(n)?"obj":Array.isArray(n)?"array":"")||("obj"===e?ke(a=Object.keys(t).sort(),Object.keys(n).sort())||a.some(function(e){return ke(t[e],n[e])}):"array"===e?t.length!==n.length||t.some(function(e,t){return ke(e,n[t])}):t!==n)}function we(n){return n&&(he(n)?Object.keys(n).reduce(function(e,t){return e[t]=we(n[t]),e},{}):Array.isArray(n)?n.map(we):n)}function Oe(e){var t,n,a,i=1,o=e=(e+"").trim();function l(e){var t=1,e=m.exec(e);return e&&(t=parseFloat(e[1]),e[2]?t=0<=t&&t<=100?t/100:1:(t<0||1=Math.abs(n)?0<=t?k:A:0<=n?L:b))})),f.position_path!==y.position_path||f.position_lineStrokeWidth!==y.position_lineStrokeWidth||[0,1].some(function(e){return f.position_plugOverheadSE[e]!==y.position_plugOverheadSE[e]||(t=v[e],n=y.position_socketXYSE[e],t.x!==n.x||t.y!==n.y||t.socketId!==n.socketId)||(t=g[e],n=y.position_socketGravitySE[e],(e=null==t?"auto":Array.isArray(t)?"array":"number")!=(null==n?"auto":Array.isArray(n)?"array":"number")||("array"==e?t[0]!==n[0]||t[1]!==n[1]:t!==n));var t,n})){switch(l.pathList.baseVal=_=[],l.pathList.animVal=null,f.position_path){case P:_.push([E(v[0]),E(v[1])]);break;case N:t="number"==typeof g[0]&&0j?(f.position_lineStrokeWidth-j)*H:0),e.socketId===b?{x:0,y:-(i=(i=(e.y-n.y)/2)=t.x:t.dirId===r?e.y>=t.y:e.x<=t.x}function f(e,t){return t.dirId===i||t.dirId===r?e.x===t.x:e.y===t.y}function y(e){return e[0]?{contain:0,notContain:1}:{contain:1,notContain:0}}function m(e,t,n){return Math.abs(t[n]-e[n])}function S(e,t,n){return"x"===n?e.x=ee?S(u[t.notContain],u[t.contain],o[t.contain]):u[t.contain].dirId)):(i=[{x:u[0].x,y:u[0].y},{x:u[1].x,y:u[1].y}],s.forEach(function(e,t){var n=0===t?1:0,a=m(i[t],i[n],o[t]);a$&&(d[a]-e<$&&(e=d[a]-$),s=Ve(n[0],n[1],(p?e:d[a]-e)/d[a]),_[a]=p?[s,n[1]]:[n[0],s],d[a]-=e)):(d[a]=d[a]||Te.apply(null,n),d[a]>$&&(d[a]-e<$&&(e=d[a]-$),s=Ne(n[0],n[1],n[2],n[3],We(n[0],n[1],n[2],n[3],p?e:d[a]-e)),o=p?(i=n[0],s.toP1):(i=n[3],s.fromP2),l=Math.atan2(i.y-s.y,s.x-i.x),r=Ae(s,o),s.x=i.x+Math.cos(l)*e,s.y=i.y+Math.sin(l)*e*-1,o.x=s.x+Math.cos(l)*r,o.y=s.y+Math.sin(l)*r*-1,_[a]=p?[s,s.toP1,s.toP2,n[3]]:[n[0],s.fromP1,s.fromP2,s],d[a]=null)):e<0&&(n=_[a=p?0:_.length-1],s=v[t].socketId,t=-c[t]["x"==(u=s===A||s===k?"x":"y")?"width":"height"],h=(e=en.outlineMax&&(t=n.outlineMax),t*=2*n.outlineBase,y=Xe(r,u.plugOutline_strokeWidthSE,e,t)||y,y=Xe(r,u.plugOutline_inStrokeWidthSE,e,u.plugOutline_colorTraSE[e]?t-se/(u.line_strokeWidth/ue.lineSize)/s.plugSizeSE[e]*2:t/2)||y)}),y)),(t.faces||U.line||U.plug||U.lineOutline||U.plugOutline)&&(U.faces=(g=(m=e).curStats,_=m.aplStats,v=m.events,E=!1,!g.line_altColor&&Xe(m,_,"line_color",S=g.line_color,v.apl_line_color)&&(m.lineFace.style.stroke=S,E=!0),Xe(m,_,"line_strokeWidth",S=g.line_strokeWidth,v.apl_line_strokeWidth)&&(m.lineShape.style.strokeWidth=S+"px",E=!0,(oe||ie)&&(je(m,m.lineShape),ie&&(je(m,m.lineFace),je(m,m.lineMaskCaps)))),Xe(m,_,"lineOutline_enabled",S=g.lineOutline_enabled,v.apl_lineOutline_enabled)&&(m.lineOutlineFace.style.display=S?"inline":"none",E=!0),g.lineOutline_enabled&&(Xe(m,_,"lineOutline_color",S=g.lineOutline_color,v.apl_lineOutline_color)&&(m.lineOutlineFace.style.stroke=S,E=!0),Xe(m,_,"lineOutline_strokeWidth",S=g.lineOutline_strokeWidth,v.apl_lineOutline_strokeWidth)&&(m.lineOutlineMaskShape.style.strokeWidth=S+"px",E=!0,ie&&(je(m,m.lineOutlineMaskCaps),je(m,m.lineOutlineFace))),Xe(m,_,"lineOutline_inStrokeWidth",S=g.lineOutline_inStrokeWidth,v.apl_lineOutline_inStrokeWidth)&&(m.lineMaskShape.style.strokeWidth=S+"px",E=!0,ie&&(je(m,m.lineOutlineMaskCaps),je(m,m.lineOutlineFace)))),Xe(m,_,"plug_enabled",S=g.plug_enabled,v.apl_plug_enabled)&&(m.plugsFace.style.display=S?"inline":"none",E=!0),g.plug_enabled&&[0,1].forEach(function(n){var e=g.plug_plugSE[n],t=e!==Y?X[q[e]]:null,a=Ze(n,t);Xe(m,_.plug_enabledSE,n,S=g.plug_enabledSE[n],v.apl_plug_enabledSE)&&(m.plugsFace.style[a.prop]=S?"url(#"+m.plugMarkerIdSE[n]+")":"none",E=!0),g.plug_enabledSE[n]&&(Xe(m,_.plug_plugSE,n,e,v.apl_plug_plugSE)&&(m.plugFaceSE[n].href.baseVal="#"+t.elmId,Ue(m,m.plugMarkerSE[n],a.orient,t.bBox,m.svg,m.plugMarkerShapeSE[n],m.plugsFace),E=!0,oe&&je(m,m.plugsFace)),Xe(m,_.plug_colorSE,n,S=g.plug_colorSE[n],v.apl_plug_colorSE)&&(m.plugFaceSE[n].style.fill=S,E=!0,(le||re||ie)&&!g.line_colorTra&&je(m,ie?m.lineMaskCaps:m.capsMaskLine)),["markerWidth","markerHeight"].forEach(function(e){var t="plug_"+e+"SE";Xe(m,_[t],n,S=g[t][n],v["apl_"+t])&&(m.plugMarkerSE[n][e].baseVal.value=S,E=!0)}),Xe(m,_.plugOutline_enabledSE,n,S=g.plugOutline_enabledSE[n],v.apl_plugOutline_enabledSE)&&(S?(m.plugFaceSE[n].style.mask="url(#"+m.plugMaskIdSE[n]+")",m.plugOutlineFaceSE[n].style.display="inline"):(m.plugFaceSE[n].style.mask="none",m.plugOutlineFaceSE[n].style.display="none"),E=!0),g.plugOutline_enabledSE[n]&&(Xe(m,_.plugOutline_plugSE,n,e,v.apl_plugOutline_plugSE)&&(m.plugOutlineFaceSE[n].href.baseVal=m.plugMaskShapeSE[n].href.baseVal=m.plugOutlineMaskShapeSE[n].href.baseVal="#"+t.elmId,[m.plugMaskSE[n],m.plugOutlineMaskSE[n]].forEach(function(e){e.x.baseVal.value=t.bBox.left,e.y.baseVal.value=t.bBox.top,e.width.baseVal.value=t.bBox.width,e.height.baseVal.value=t.bBox.height}),E=!0),Xe(m,_.plugOutline_colorSE,n,S=g.plugOutline_colorSE[n],v.apl_plugOutline_colorSE)&&(m.plugOutlineFaceSE[n].style.fill=S,E=!0,ie&&(je(m,m.lineMaskCaps),je(m,m.lineOutlineMaskCaps))),Xe(m,_.plugOutline_strokeWidthSE,n,S=g.plugOutline_strokeWidthSE[n],v.apl_plugOutline_strokeWidthSE)&&(m.plugOutlineMaskShapeSE[n].style.strokeWidth=S+"px",E=!0),Xe(m,_.plugOutline_inStrokeWidthSE,n,S=g.plugOutline_inStrokeWidthSE[n],v.apl_plugOutline_inStrokeWidthSE)&&(m.plugMaskShapeSE[n].style.strokeWidth=S+"px",E=!0)))}),E)),(t.position||U.line||U.plug)&&(U.position=Ke(e)),(t.path||U.position)&&(U.path=(k=(x=e).curStats,I=x.aplStats,M=x.pathList.animVal||x.pathList.baseVal,w=k.path_edge,C=!1,M&&(w.x1=w.x2=M[0][0].x,w.y1=w.y2=M[0][0].y,k.path_pathData=b=Be(M,function(e){e.xw.x2&&(w.x2=e.x),e.y>w.y2&&(w.y2=e.y)}),Fe(b,I.path_pathData)&&(x.linePath.setPathData(b),I.path_pathData=b,C=!0,ie?(je(x,x.plugsFace),je(x,x.lineMaskCaps)):oe&&je(x,x.linePath),x.events.apl_path&&x.events.apl_path.forEach(function(e){e(x,b)}))),C)),U.viewBox=(M=(O=e).curStats,I=O.aplStats,C=M.path_edge,L=M.viewBox_bBox,A=I.viewBox_bBox,V=O.svg.viewBox.baseVal,P=O.svg.style,N=!1,I=Math.max(M.line_strokeWidth/2,M.viewBox_plugBCircleSE[0]||0,M.viewBox_plugBCircleSE[1]||0),T={x1:C.x1-I,y1:C.y1-I,x2:C.x2+I,y2:C.y2+I},O.events.new_edge4viewBox&&O.events.new_edge4viewBox.forEach(function(e){e(O,T)}),L.x=M.lineMask_x=M.lineOutlineMask_x=M.maskBGRect_x=T.x1,L.y=M.lineMask_y=M.lineOutlineMask_y=M.maskBGRect_y=T.y1,L.width=T.x2-T.x1,L.height=T.y2-T.y1,["x","y","width","height"].forEach(function(e){var t;(t=L[e])!==A[e]&&(V[e]=A[e]=t,P[Q[e]]=t+("x"===e||"y"===e?O.bodyOffset[e]:0)+"px",N=!0)}),N),U.mask=(R=(W=e).curStats,F=W.aplStats,G=!1,R.plug_enabled?[0,1].forEach(function(e){R.capsMaskMarker_enabledSE[e]=R.plug_enabledSE[e]&&R.plug_colorTraSE[e]||R.plugOutline_enabledSE[e]&&R.plugOutline_colorTraSE[e]}):R.capsMaskMarker_enabledSE[0]=R.capsMaskMarker_enabledSE[1]=!1,R.capsMaskMarker_enabled=R.capsMaskMarker_enabledSE[0]||R.capsMaskMarker_enabledSE[1],R.lineMask_outlineMode=R.lineOutline_enabled,R.caps_enabled=R.capsMaskMarker_enabled||R.capsMaskAnchor_enabledSE[0]||R.capsMaskAnchor_enabledSE[1],R.lineMask_enabled=R.caps_enabled||R.lineMask_outlineMode,(R.lineMask_enabled&&!R.lineMask_outlineMode||R.lineOutline_enabled)&&["x","y"].forEach(function(e){var t="maskBGRect_"+e;Xe(W,F,t,B=R[t])&&(W.maskBGRect[e].baseVal.value=B,G=!0)}),Xe(W,F,"lineMask_enabled",B=R.lineMask_enabled)&&(W.lineFace.style.mask=B?"url(#"+W.lineMaskId+")":"none",G=!0,re&&je(W,W.lineMask)),R.lineMask_enabled&&(Xe(W,F,"lineMask_outlineMode",B=R.lineMask_outlineMode)&&(B?(W.lineMaskBG.style.display="none",W.lineMaskShape.style.display="inline"):(W.lineMaskBG.style.display="inline",W.lineMaskShape.style.display="none"),G=!0),["x","y"].forEach(function(e){var t="lineMask_"+e;Xe(W,F,t,B=R[t])&&(W.lineMask[e].baseVal.value=B,G=!0)}),Xe(W,F,"caps_enabled",B=R.caps_enabled)&&(W.lineMaskCaps.style.display=W.lineOutlineMaskCaps.style.display=B?"inline":"none",G=!0,re&&je(W,W.capsMaskLine)),R.caps_enabled&&([0,1].forEach(function(e){var t;Xe(W,F.capsMaskAnchor_enabledSE,e,B=R.capsMaskAnchor_enabledSE[e])&&(W.capsMaskAnchorSE[e].style.display=B?"inline":"none",G=!0,re&&je(W,W.lineMask)),R.capsMaskAnchor_enabledSE[e]&&(Fe(t=R.capsMaskAnchor_pathDataSE[e],F.capsMaskAnchor_pathDataSE[e])&&(W.capsMaskAnchorSE[e].setPathData(t),F.capsMaskAnchor_pathDataSE[e]=t,G=!0),Xe(W,F.capsMaskAnchor_strokeWidthSE,e,B=R.capsMaskAnchor_strokeWidthSE[e])&&(W.capsMaskAnchorSE[e].style.strokeWidth=B+"px",G=!0))}),Xe(W,F,"capsMaskMarker_enabled",B=R.capsMaskMarker_enabled)&&(W.capsMaskLine.style.display=B?"inline":"none",G=!0),R.capsMaskMarker_enabled&&[0,1].forEach(function(n){var e=R.capsMaskMarker_plugSE[n],t=e!==Y?X[q[e]]:null,a=Ze(n,t);Xe(W,F.capsMaskMarker_enabledSE,n,B=R.capsMaskMarker_enabledSE[n])&&(W.capsMaskLine.style[a.prop]=B?"url(#"+W.lineMaskMarkerIdSE[n]+")":"none",G=!0),R.capsMaskMarker_enabledSE[n]&&(Xe(W,F.capsMaskMarker_plugSE,n,e)&&(W.capsMaskMarkerShapeSE[n].href.baseVal="#"+t.elmId,Ue(W,W.capsMaskMarkerSE[n],a.orient,t.bBox,W.svg,W.capsMaskMarkerShapeSE[n],W.capsMaskLine),G=!0,oe&&(je(W,W.capsMaskLine),je(W,W.lineFace))),["markerWidth","markerHeight"].forEach(function(e){var t="capsMaskMarker_"+e+"SE";Xe(W,F[t],n,B=R[t][n])&&(W.capsMaskMarkerSE[n][e].baseVal.value=B,G=!0)}))}))),R.lineOutline_enabled&&["x","y"].forEach(function(e){var t="lineOutlineMask_"+e;Xe(W,F,t,B=R[t])&&(W.lineOutlineMask[e].baseVal.value=B,G=!0)}),G),t.effect&&(j=(D=e).curStats,H=D.aplStats,Object.keys(Z).forEach(function(e){var t=Z[e],n=e+"_enabled",a=e+"_options",e=j[a];Xe(D,H,n,z=j[n])?(z&&(H[a]=we(e)),t[z?"init":"remove"](D)):z&&ke(e,H[a])&&(t.remove(D),H[n]=!0,H[a]=we(e),t.init(D))})),(le||re)&&U.line&&!U.path&&je(e,e.lineShape),le&&U.plug&&!U.line&&je(e,e.plugsFace),He(e)}function et(e,t){return{duration:(pe(e.duration)&&0i.x2&&(i.x2=e.x2),e.y2>i.y2&&(i.y2=e.y2),["x","y"].forEach(function(e){var t,n="dropShadow_"+e;o[n]=t=i[e+"1"],Xe(a,l,n,t)&&(a.efc_dropShadow_elmFilter[e].baseVal.value=t)}))}}},Object.keys(Z).forEach(function(e){var t=Z[e],n=t.stats;n[e+"_enabled"]={iniValue:!1},n[e+"_options"]={hasProps:!0},t.anim&&(n[e+"_animOptions"]={},n[e+"_animId"]={})}),w={none:{defaultAnimOptions:{},init:function(e,t){var n=e.curStats;n.show_animId&&(g.remove(n.show_animId),n.show_animId=null),w.none.start(e,t)},start:function(e,t){w.none.stop(e,!0)},stop:function(e,t,n){var a=e.curStats;return n=null!=n?n:e.aplStats.show_on,a.show_inAnim=!1,t&&Je(e,n),n?1:0}},fade:{defaultAnimOptions:{duration:300,timing:"linear"},init:function(n,e){var t=n.curStats,a=n.aplStats;t.show_animId&&g.remove(t.show_animId),t.show_animId=g.add(function(e){return e},function(e,t){t?w.fade.stop(n,!0):(n.svg.style.opacity=e+"",ie&&(je(n,n.svg),He(n)))},a.show_animOptions.duration,1,a.show_animOptions.timing,null,!1),w.fade.start(n,e)},start:function(e,t){var n,a=e.curStats;a.show_inAnim&&(n=g.stop(a.show_animId)),Je(e,1),a.show_inAnim=!0,g.start(a.show_animId,!e.aplStats.show_on,null!=t?t:n)},stop:function(e,t,n){var a,i=e.curStats;return n=null!=n?n:e.aplStats.show_on,a=i.show_inAnim?g.stop(i.show_animId):n?1:0,i.show_inAnim=!1,t&&(e.svg.style.opacity=n?"":"0",Je(e,n)),a}},draw:{defaultAnimOptions:{duration:500,timing:[.58,0,.42,1]},init:function(n,e){var t=n.curStats,a=n.aplStats,o=n.pathList.baseVal,i=Re(o),l=i.segsLen,r=i.lenAll;t.show_animId&&g.remove(t.show_animId),t.show_animId=g.add(function(e){var t,n,a,i=-1;if(0===e)n=[[o[0][0],o[0][0]]];else if(1===e)n=o;else{for(t=r*e,n=[];t>=l[++i];)n.push(o[i]),t-=l[i];t&&(2===(a=o[i]).length?n.push([a[0],Ve(a[0],a[1],t/l[i])]):(e=Ne(a[0],a[1],a[2],a[3],We(a[0],a[1],a[2],a[3],t)),n.push([a[0],e.fromP1,e.fromP2,e])))}return n},function(e,t){t?w.draw.stop(n,!0):(n.pathList.animVal=e,$e(n,{path:!0}))},a.show_animOptions.duration,1,a.show_animOptions.timing,null,!1),w.draw.start(n,e)},start:function(e,t){var n,a=e.curStats;a.show_inAnim&&(n=g.stop(a.show_animId)),Je(e,1),a.show_inAnim=!0,Ge(e,"apl_position",w.draw.update),g.start(a.show_animId,!e.aplStats.show_on,null!=t?t:n)},stop:function(e,t,n){var a,i=e.curStats;return n=null!=n?n:e.aplStats.show_on,a=i.show_inAnim?g.stop(i.show_animId):n?1:0,i.show_inAnim=!1,t&&(e.pathList.animVal=n?null:[[e.pathList.baseVal[0][0],e.pathList.baseVal[0][0]]],$e(e,{path:!0}),Je(e,n)),a},update:function(e){De(e,"apl_position",w.draw.update),e.curStats.show_inAnim?w.draw.init(e,w.draw.stop(e)):e.aplStats.show_animOptions={}}}},[["start","anchorSE",0],["end","anchorSE",1],["color","lineColor"],["size","lineSize"],["startSocketGravity","socketGravitySE",0],["endSocketGravity","socketGravitySE",1],["startPlugColor","plugColorSE",0],["endPlugColor","plugColorSE",1],["startPlugSize","plugSizeSE",0],["endPlugSize","plugSizeSE",1],["outline","lineOutlineEnabled"],["outlineColor","lineOutlineColor"],["outlineSize","lineOutlineSize"],["startPlugOutline","plugOutlineEnabledSE",0],["endPlugOutline","plugOutlineEnabledSE",1],["startPlugOutlineColor","plugOutlineColorSE",0],["endPlugOutlineColor","plugOutlineColorSE",1],["startPlugOutlineSize","plugOutlineSizeSE",0],["endPlugOutlineSize","plugOutlineSizeSE",1]].forEach(function(e){var t=e[0],n=e[1],a=e[2];Object.defineProperty(ot.prototype,t,{get:function(){var e=null!=a?Se[this._id].options[n][a]:n?Se[this._id].options[n]:Se[this._id].options[t];return null==e?D:we(e)},set:lt(t),enumerable:!0})}),[["path",R],["startSocket",V,"socketSE",0],["endSocket",V,"socketSE",1],["startPlug",F,"plugSE",0],["endPlug",F,"plugSE",1]].forEach(function(e){var a=e[0],i=e[1],o=e[2],l=e[3];Object.defineProperty(ot.prototype,a,{get:function(){var t,n=null!=l?Se[this._id].options[o][l]:o?Se[this._id].options[o]:Se[this._id].options[a];return n?Object.keys(i).some(function(e){return i[e]===n&&(t=e,!0)})?t:new Error("It's broken"):D},set:lt(a),enumerable:!0})}),Object.keys(Z).forEach(function(n){var a=Z[n];Object.defineProperty(ot.prototype,n,{get:function(){var s,e,t=Se[this._id].options[n];return he(t)?(s=t,e=a.optionsConf.reduce(function(e,t){var n,a=t[0],i=t[1],o=t[2],l=t[3],t=t[4],r=null!=t?s[l][t]:l?s[l]:s[i];return e[i]="id"===a?r?Object.keys(o).some(function(e){return o[e]===r&&(n=e,!0)})?n:new Error("It's broken"):D:null==r?D:we(r),e},{}),a.anim&&(e.animation=we(s.animation)),e):t},set:lt(n),enumerable:!0})}),["startLabel","endLabel","middleLabel"].forEach(function(e,n){Object.defineProperty(ot.prototype,e,{get:function(){var e=Se[this._id],t=e.options;return t.labelSEM[n]&&!e.optionIsAttach.labelSEM[n]?_e[t.labelSEM[n]._id].text:t.labelSEM[n]||""},set:lt(e),enumerable:!0})}),ot.prototype.setOptions=function(e){return it(Se[this._id],e),this},ot.prototype.position=function(){return $e(Se[this._id],{position:!0}),this},ot.prototype.remove=function(){var t=Se[this._id],n=t.curStats;Object.keys(Z).forEach(function(e){e+="_animId";n[e]&&g.remove(n[e])}),n.show_animId&&g.remove(n.show_animId),t.attachments.slice().forEach(function(e){at(t,e)}),t.baseWindow&&t.svg&&t.baseWindow.document.body.removeChild(t.svg),delete Se[this._id]},ot.prototype.show=function(e,t){return tt(Se[this._id],!0,e,t),this},ot.prototype.hide=function(e,t){return tt(Se[this._id],!1,e,t),this},o=function(t){t&&_e[t._id]&&(t.boundTargets.slice().forEach(function(e){at(e.props,t,!0)}),t.conf.remove&&t.conf.remove(t),delete _e[t._id])},rt.prototype.remove=function(){var t=this,n=_e[t._id];n&&(n.boundTargets.slice().forEach(function(e){n.conf.removeOption(n,e)}),ze(function(){var e=_e[t._id];e&&(console.error("LeaderLineAttachment was not removed by removeOption"),o(e))}))},M=rt,window.LeaderLineAttachment=M,I=function(e,t){return e instanceof M&&(!(e.isRemoved||t&&_e[e._id].conf.type!==t)||null)},O={pointAnchor:{type:"anchor",argOptions:[{optionName:"element",type:Me}],init:function(e,t){return e.element=O.pointAnchor.checkElement(t.element),e.x=O.pointAnchor.parsePercent(t.x,!0)||[.5,!0],e.y=O.pointAnchor.parsePercent(t.y,!0)||[.5,!0],!0},removeOption:function(e,t){var n=t.props,a={},i=e.element,e=n.options.anchorSE["start"===t.optionName?1:0];i===e&&(i=e===document.body?new M(O.pointAnchor,[i]):document.body),a[t.optionName]=i,it(n,a)},getBBoxNest:function(e,t){var n=Le(e.element,t.baseWindow),a=n.width,t=n.height;return n.width=n.height=0,n.left=n.right=n.left+e.x[0]*(e.x[1]?a:1),n.top=n.bottom=n.top+e.y[0]*(e.y[1]?t:1),n},parsePercent:function(e,t){var n,a,i=!1;return pe(e)?a=e:"string"==typeof e&&(n=m.exec(e))&&n[2]&&(i=0!==(a=parseFloat(n[1])/100)),null!=a&&(t||0<=a)?[a,i]:null},checkElement:function(e){if(null==e)e=document.body;else if(!Me(e))throw new Error("`element` must be Element");return e}},areaAnchor:{type:"anchor",argOptions:[{optionName:"element",type:Me},{optionName:"shape",type:"string"}],stats:{color:{},strokeWidth:{},elementWidth:{},elementHeight:{},elementLeft:{},elementTop:{},pathListRel:{},bBoxRel:{},pathData:{},viewBoxBBox:{hasProps:!0},dashLen:{},dashGap:{}},init:function(a,e){var t,n=[];return a.element=O.pointAnchor.checkElement(e.element),"string"==typeof e.color&&(a.color=e.color.trim()),"string"==typeof e.fillColor&&(a.fill=e.fillColor.trim()),pe(e.size)&&0<=e.size&&(a.size=e.size),e.dash&&(a.dash=!0,pe(e.dash.len)&&0i.right&&(i.right=t),ei.bottom&&(i.bottom=e)):i={left:t,right:t,top:e,bottom:e},o?S.pathListRel.push([o,{x:t,y:e}]):S.pathListRel=[],o={x:t,y:e}}),S.pathListRel.push([]),e=S.strokeWidth/2,e=[{x:i.left-e,y:i.top-e},{x:i.right+e,y:i.bottom+e}],S.bBoxRel={left:e[0].x,top:e[0].y,right:e[1].x,bottom:e[1].y,width:e[1].x-e[0].x,height:e[1].y-e[0].y}}v.pathListRel=v.bBoxRel=!0}return(v.pathListRel||v.elementLeft||v.elementTop)&&(S.pathData=Be(S.pathListRel,function(e){e.x+=n.left,e.y+=n.top})),Xe(t,g,"strokeWidth",a=S.strokeWidth)&&(t.path.style.strokeWidth=a+"px"),Fe(a=S.pathData,g.pathData)&&(t.path.setPathData(a),g.pathData=a,v.pathData=!0),t.dash&&(!v.pathData&&(!v.strokeWidth||t.dashLen&&t.dashGap)||(S.dashLen=t.dashLen||2*S.strokeWidth,S.dashGap=t.dashGap||S.strokeWidth),v.dash=Xe(t,g,"dashLen",S.dashLen)||v.dash,v.dash=Xe(t,g,"dashGap",S.dashGap)||v.dash,v.dash&&(t.path.style.strokeDasharray=g.dashLen+","+g.dashGap)),d=S.viewBoxBBox,f=g.viewBoxBBox,y=t.svg.viewBox.baseVal,m=t.svg.style,d.x=S.bBoxRel.left+n.left,d.y=S.bBoxRel.top+n.top,d.width=S.bBoxRel.width,d.height=S.bBoxRel.height,["x","y","width","height"].forEach(function(e){(a=d[e])!==f[e]&&(y[e]=f[e]=a,m[Q[e]]=a+("x"===e||"y"===e?t.bodyOffset[e]:0)+"px")}),v.strokeWidth||v.pathListRel||v.bBoxRel}},mouseHoverAnchor:{type:"anchor",argOptions:[{optionName:"element",type:Me},{optionName:"showEffectName",type:"string"}],style:{backgroundImage:"url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ij48cG9seWdvbiBwb2ludHM9IjI0LDAgMCw4IDgsMTEgMCwxOSA1LDI0IDEzLDE2IDE2LDI0IiBmaWxsPSJjb3JhbCIvPjwvc3ZnPg==')",backgroundSize:"",backgroundRepeat:"no-repeat",backgroundColor:"#f8f881",cursor:"default"},hoverStyle:{backgroundImage:"none",backgroundColor:"#fadf8f"},padding:{top:1,right:15,bottom:1,left:2},minHeight:15,backgroundPosition:{right:2,top:2},backgroundSize:{width:12,height:12},dirKeys:[["top","Top"],["right","Right"],["bottom","Bottom"],["left","Left"]],init:function(a,i){var n,t,e,o,l,r,s,u,h,p=O.mouseHoverAnchor,c={};if(a.element=O.pointAnchor.checkElement(i.element),s=a.element,!((u=s.ownerDocument)&&(h=u.defaultView)&&h.HTMLElement&&s instanceof h.HTMLElement))throw new Error("`element` must be HTML element");return p.style.backgroundSize=p.backgroundSize.width+"px "+p.backgroundSize.height+"px",["style","hoverStyle"].forEach(function(e){var n=p[e];a[e]=Object.keys(n).reduce(function(e,t){return e[t]=n[t],e},{})}),"inline"===(n=a.element.ownerDocument.defaultView.getComputedStyle(a.element,"")).display?a.style.display="inline-block":"none"===n.display&&(a.style.display="block"),O.mouseHoverAnchor.dirKeys.forEach(function(e){var t=e[0],e="padding"+e[1];parseFloat(n[e])e.x2&&(e.x2=n.x2),n.y2>e.y2&&(e.y2=n.y2)},newText:function(e,t,n,a,i){var o,l,r=t.createElementNS(ae,"text");return r.textContent=e,[r.x,r.y].forEach(function(e){var t=n.createSVGLength();t.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX,0),e.baseVal.initialize(t)}),"boolean"!=typeof h&&(h="paintOrder"in r.style),i&&!h?(o=t.createElementNS(ae,"defs"),r.id=a,o.appendChild(r),(l=(e=t.createElementNS(ae,"g")).appendChild(t.createElementNS(ae,"use"))).href.baseVal="#"+a,(t=e.appendChild(t.createElementNS(ae,"use"))).href.baseVal="#"+a,(l=l.style).strokeLinejoin="round",{elmPosition:r,styleText:r.style,styleFill:t.style,styleStroke:l,styleShow:e.style,elmsAppend:[o,e]}):(l=r.style,i&&(l.strokeLinejoin="round",l.paintOrder="stroke"),{elmPosition:r,styleText:l,styleFill:l,styleStroke:i?l:null,styleShow:l,elmsAppend:[r]})},getMidPoint:function(e,t){var n,a,i=Re(e),o=i.segsLen,i=i.lenAll,l=-1,r=i/2+(t||0);if(r<=0)return 2===(n=e[0]).length?Ve(n[0],n[1],0):Ne(n[0],n[1],n[2],n[3],0);if(i<=r)return 2===(n=e[e.length-1]).length?Ve(n[0],n[1],1):Ne(n[0],n[1],n[2],n[3],1);for(a=[];r>o[++l];)a.push(e[l]),r-=o[l];return 2===(n=e[l]).length?Ve(n[0],n[1],r/o[l]):Ne(n[0],n[1],n[2],n[3],We(n[0],n[1],n[2],n[3],r))},initSvg:function(t,n){var e,a,i=O.captionLabel.newText(t.text,n.baseWindow.document,n.svg,C+"-captionLabel-"+t._id,t.outlineColor);["elmPosition","styleFill","styleShow","elmsAppend"].forEach(function(e){t[e]=i[e]}),t.isShown=!1,t.styleShow.visibility="hidden",O.captionLabel.textStyleProps.forEach(function(e){null!=t[e]&&(i.styleText[e]=t[e])}),i.elmsAppend.forEach(function(e){n.svg.appendChild(e)}),e=i.elmPosition.getBBox(),t.width=e.width,t.height=e.height,t.outlineColor&&(a=e.height/9,i.styleStroke.strokeWidth=(a=10c?((t=d.points)[1]=Pe(t[0],t[1],-c),d.len=Ae(t[0],t[1])):(d.points=null,d.len=0),e.len>c+n?((t=e.points)[0]=Pe(t[1],t[0],-(c+n)),e.len=Ae(t[0],t[1])):(e.points=null,e.len=0)),e):null}),f.reduce(function(t,e){var n=e.points;return n&&(a&&y(n[0],a)||t.push({type:"M",values:[n[0].x,n[0].y]}),"line"===e.type?t.push({type:"L",values:[n[1].x,n[1].y]}):(n.shift(),n.forEach(function(e){t.push({type:"L",values:[e.x,e.y]})})),a=n[n.length-1]),t},[])},newText:function(e,t,n,a){var i,o,l,r,s=t.createElementNS(ae,"defs"),u=s.appendChild(t.createElementNS(ae,"path"));return u.id=i=n+"-path",(l=(o=t.createElementNS(ae,"text")).appendChild(t.createElementNS(ae,"textPath"))).href.baseVal="#"+i,l.startOffset.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX,0),l.textContent=e,"boolean"!=typeof h&&(h="paintOrder"in o.style),a&&!h?(o.id=e=n+"-text",s.appendChild(o),(r=(n=t.createElementNS(ae,"g")).appendChild(t.createElementNS(ae,"use"))).href.baseVal="#"+e,(t=n.appendChild(t.createElementNS(ae,"use"))).href.baseVal="#"+e,(r=r.style).strokeLinejoin="round",{elmPosition:o,elmPath:u,elmOffset:l,styleText:o.style,styleFill:t.style,styleStroke:r,styleShow:n.style,elmsAppend:[s,n]}):(r=o.style,a&&(r.strokeLinejoin="round",r.paintOrder="stroke"),{elmPosition:o,elmPath:u,elmOffset:l,styleText:r,styleFill:r,styleStroke:a?r:null,styleShow:r,elmsAppend:[s,o]})},initSvg:function(t,n){var e,a,i,o=O.pathLabel.newText(t.text,n.baseWindow.document,C+"-pathLabel-"+t._id,t.outlineColor);["elmPosition","elmPath","elmOffset","styleFill","styleShow","elmsAppend"].forEach(function(e){t[e]=o[e]}),t.isShown=!1,t.styleShow.visibility="hidden",O.captionLabel.textStyleProps.forEach(function(e){null!=t[e]&&(o.styleText[e]=t[e])}),o.elmsAppend.forEach(function(e){n.svg.appendChild(e)}),o.elmPath.setPathData([{type:"M",values:[0,100]},{type:"h",values:[100]}]),le&&(i=o.elmOffset.href.baseVal,o.elmOffset.href.baseVal=""),e=o.elmPosition.getBBox(),le&&(o.elmOffset.href.baseVal=i),o.styleText.textAnchor=["start","end","middle"][t.semIndex],2!==t.semIndex||t.lineOffset||o.elmOffset.startOffset.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PERCENTAGE,50),t.height=e.height,t.outlineColor&&(a=e.height/9,o.styleStroke.strokeWidth=(a=10 { + // Data send from extension + const message = event.data; + + switch (message.command) { + case "updateButtons": + document.querySelector("#nextButton").disabled = !message.next; + document.querySelector("#prevButton").disabled = !message.prev; + document.querySelector("#firstButton").disabled = !message.first; + document.querySelector("#lastButton").disabled = !message.last; + break; + case "updateContent": + const traceMax = message.traceLen - 1; + if (traceMax < 0) { + traceMax = 0; + } + document.querySelector("#traceSlider").max = traceMax; + document.querySelector("#traceSlider").value = message.traceIndex; + document.querySelector("#traceMax").innerHTML = "/" + (message.traceComplete ? traceMax.toString() : "?"); + document.querySelector("#indexCounter").innerHTML = message.traceIndex; + updateVisualization(message.traceElem); + updateIntend(message.traceElem); + updateRefArrows(message.traceElem); + break; + } +}); + +/** + * Updates the Visualization in the Webview, with the given BackendTraceElem. + * + * @param traceElem A BackendTraceElem with 3 fields (line, stack, heap) + */ +function updateVisualization(traceElem) { + const data = ` +
+
+
+ Frames +
+
+
+
+
+ Objects +
+
+
+
+
+
+ ${traceElem[1]} +
+
+ ${traceElem[2]} +
+
+ `; + const viz = document.getElementById("viz"); + viz.innerHTML = data; + viz.addEventListener("scroll", () => { + updateRefArrows(traceElem); + }); + viz.scrollTo(0, viz.scrollHeight); + const stdoutLog = document.getElementById("stdout-log"); + stdoutLog.innerHTML = traceElem[4]; + stdoutLog.scrollTo(0, stdoutLog.scrollHeight); +} + +/** + * Updates the indendation for heap elements, if a other heap element references it. + * + * @param traceElem A BackendTraceElem with 3 fields (line, stack, heap) + */ +function updateIntend(traceElem) { + const heapTags = traceElem[2].match(/(?<=startPointer)[0-9]+/g); + if (heapTags) { + heapTags.forEach((tag) => { + const element = document.getElementById("objectItem" + tag); + if (element) { element.classList.add("object-intendation"); } + }); + } +} + +/** + * Updates the Reference Arrows from frame items to heap & heap items to heap items. + * + * @param traceElem A BackendTraceElem with 3 fields (line, stack, heap) + */ +function updateRefArrows(traceElem) { + const tags = getCurrentTags(traceElem); + refTags.forEach((tag) => tag.remove()); + refTags = []; + + if (!tags) { + return; + } + + refTags = tags + .filter((tag) => tag.elem1 && tag.elem2) + .map((tag) => { + return new LeaderLine(tag.elem1, tag.elem2, { + size: 2, + path: "magnet", + startSocket: "right", + endSocket: "left", + startPlug: "square", + startSocketGravity: [50, -10], + endSocketGravity: [-5, -5], + endPlug: "arrow1", + color: getColor(tag), + }); + }); +} + +/** + * Retrieves all id's on the frame side and heap side, that have a potential start or end pointer in there id. + * Is later used to create Reference Arrows. + * + * @param traceElem A BackendTraceElem with 3 fields (line, stack, heap) + * @returns A list with all ids that have either a start or end pointer id in the html + */ +function getCurrentTags(traceElem) { + const stackTags = traceElem[1].match(/(?<=id=")(.+)Pointer[0-9]+/g); + const heapTags = traceElem[2].match(/(?<=startPointer)[0-9]+/g); + const uniqueId = traceElem[2].match(/(?<=)\d+(?=startPointer)/g); + + if (!stackTags) { + return; + } + + const stackRefs = stackTags.map((tag) => { + const id = tag.match(/(?<=.*Pointer)[\d]+/g); + return { + tag: id, + elem1: document.getElementById(tag), + elem2: document.getElementById("heapEndPointer" + id), + }; + }); + + let heapRefs = []; + if (heapTags) { + heapRefs = heapTags.map((reference, index) => { + return { + tag: reference, + elem1: document.getElementById( + uniqueId[index] + "startPointer" + reference + ), + elem2: document.getElementById("heapEndPointer" + reference), + }; + }); + } + + return [...heapRefs, ...stackRefs]; +} + +/** + * Creates a color based on the tag number (variable reference). + * + * @param tag The tag number (variable reference) is used to create a color. + * @returns + */ +function getColor(tag) { + const hue = ((0.618033988749895 + tag.tag / 10) % 1) * 100; + return `hsl(${hue}, 60%, 45%)`; +} + +function onLoad() { + document.querySelector("#nextButton").disabled = false; + document.querySelector("#lastButton").disabled = false; + document.querySelector("#prevButton").disabled = true; + document.querySelector("#firstButton").disabled = true; +} + +async function onClick(type) { + await vscode.postMessage({ command: "onClick", type: type }); +} + +async function onSlide(sliderValue) { + await vscode.postMessage({ command: "onSlide", sliderValue: sliderValue }); +} diff --git a/src/programflow-visualization/frontend/visualization_panel.ts b/src/programflow-visualization/frontend/visualization_panel.ts new file mode 100644 index 00000000..5d564fd9 --- /dev/null +++ b/src/programflow-visualization/frontend/visualization_panel.ts @@ -0,0 +1,285 @@ +import * as vscode from 'vscode'; +import { nextLineExecuteHighlightType } from '../constants'; +import path = require('path'); +import { HTMLGenerator } from './HTMLGenerator'; +import { MessagePort } from 'worker_threads'; +import { cacheTrace } from '../trace_cache'; + +const FRONTEND_RESOURCE_PATH = 'src/programflow-visualization/frontend/resources'; + +export class VisualizationPanel { + private _panel: vscode.WebviewPanel | undefined; + private readonly _style: vscode.Uri; + private readonly _script: vscode.Uri; + private readonly _lineScript: vscode.Uri; + private readonly _fileHash: string; + private readonly _tracePort: MessagePort | null; + private _backendTrace: PartialBackendTrace; + private _trace: FrontendTrace; + private _traceIndex: number; + private _tracePortSelfClose: boolean; + + private constructor(context: vscode.ExtensionContext, filePath: string, fileHash: string, trace: BackendTrace, tracePort: MessagePort | null) { + this._fileHash = fileHash; + this._tracePort = tracePort; + this._backendTrace = { trace: trace, complete: trace.length > 0 }; + this._trace = []; + const htmlGenerator = new HTMLGenerator(); + trace.forEach(traceElement => { + this._trace.push(htmlGenerator.generateHTML(traceElement)); + }); + this._traceIndex = 0; + const panel = vscode.window.createWebviewPanel( + 'programflow-visualization', + `Visualization: ${path.basename(filePath)}`, + vscode.ViewColumn.Beside, + { + enableScripts: true, + localResourceRoots: [vscode.Uri.file(path.join(context.extensionPath, FRONTEND_RESOURCE_PATH))], + } + ); + + // Get path to resource on disk + const stylesFile = vscode.Uri.file(path.join(context.extensionPath, FRONTEND_RESOURCE_PATH, 'webview.css')); + const scriptFile = vscode.Uri.file(path.join(context.extensionPath, FRONTEND_RESOURCE_PATH, 'webview.js')); + const lineFile = vscode.Uri.file(path.join(context.extensionPath, FRONTEND_RESOURCE_PATH, 'leader-line.min.js')); + // And get the special URI to use with the webview + this._style = panel.webview.asWebviewUri(stylesFile); + this._script = panel.webview.asWebviewUri(scriptFile); + this._lineScript = panel.webview.asWebviewUri(lineFile); + this._panel = panel; + + this._panel.onDidChangeViewState(async (e) => { + if (e.webviewPanel.active) { + await this.postMessagesToWebview('updateContent'); + } + }); + + this._tracePortSelfClose = false; + this._panel.onDidDispose( + async () => { + this._tracePortSelfClose = true; + this._tracePort?.close(); + this.updateLineHighlight(true); + this._panel = undefined; + }, + null, + context.subscriptions + ); + + vscode.window.onDidChangeActiveTextEditor(_ => { + if (this._panel?.active) { + this.updateLineHighlight(); + } + }, undefined, context.subscriptions); + + + // Message Receivers + this._panel.webview.onDidReceiveMessage( + (msg) => { + switch (msg.command) { + case 'onClick': + return this.onClick(msg.type); + case 'onSlide': + return this.onSlide(msg.sliderValue); + } + }, + undefined, + context.subscriptions + ); + + this.updateLineHighlight(); + this.initWebviewContent(); + + this._tracePort?.on('message', async (backendTraceElem) => { + const firstElement = this._trace.length === 0; + this._backendTrace.trace.push(backendTraceElem); + this._trace.push((new HTMLGenerator()).generateHTML(backendTraceElem)); + await this.postMessagesToWebview('updateButtons', 'updateContent'); + if (firstElement) { + this.updateLineHighlight(); + } + }); + this._tracePort?.on('close', async () => { + if (!this._tracePortSelfClose) { + this._backendTrace.complete = true; + await cacheTrace(context, this._fileHash, this._backendTrace.trace); + await this.postMessagesToWebview('updateContent'); + } + }); + } + + public static async getVisualizationPanel( + context: vscode.ExtensionContext, + filePath: string, + fileHash: string, + trace: BackendTrace, + tracePort: MessagePort | null + ): Promise { + return new VisualizationPanel(context, filePath, fileHash, trace, tracePort); + } + + // TODO: Look if Typescript is possible OR do better documentation in all files + public initWebviewContent() { + this._panel!.webview.html = ` + + + + + + + + + Code Visualization + + +
+
+
+ Frames +
+
+
+ Objects +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+

Step 

+

0

+

/?

+
+
+ + + + +
+
+
+

+          
+        
+ + + `; + } + + private async updateLineHighlight(remove: boolean = false) { + if (this._trace.length === 0) { + return; + } + let editor: vscode.TextEditor | undefined = vscode.window.visibleTextEditors.filter( + editor => path.basename(editor.document.uri.path) === path.basename(this._trace[this._traceIndex][3]!) + )[0]; + + const openPath = vscode.Uri.parse(this._trace[this._traceIndex][3]!); + if (!editor || editor.document.uri.path !== openPath.path) { + await vscode.commands.executeCommand('workbench.action.focusFirstEditorGroup'); + const document = await vscode.workspace.openTextDocument(openPath); + editor = await vscode.window.showTextDocument(document); + } + + if (remove || editor.document.lineCount < this._trace[this._traceIndex][0]) { + editor.setDecorations(nextLineExecuteHighlightType, []); + } else { + this.setNextLineHighlighting(editor); + } + } + + private setNextLineHighlighting(editor: vscode.TextEditor) { + if (this._trace.length === 0) { + return; + } + const nextLine = this._trace[this._traceIndex][0] - 1; + + if (nextLine > -1) { + this.setEditorDecorations(editor, nextLineExecuteHighlightType, nextLine); + } + } + + private setEditorDecorations(editor: vscode.TextEditor, highlightType: vscode.TextEditorDecorationType, line: number) { + editor.setDecorations( + highlightType, + this.createDecorationOptions( + new vscode.Range(new vscode.Position(line, 0), new vscode.Position(line, 999)) + ) + ); + } + + private async onClick(type: string) { + this.updateTraceIndex(type); + await this.postMessagesToWebview('updateButtons', 'updateContent'); + this.updateLineHighlight(); + } + + private async onSlide(sliderValue: number) { + this._traceIndex = Number(sliderValue); + await this.postMessagesToWebview('updateButtons', 'updateContent'); + this.updateLineHighlight(); + } + + private updateTraceIndex(actionType: string) { + switch (actionType) { + case 'next': ++this._traceIndex; + break; + case 'prev': --this._traceIndex; + break; + case 'first': this._traceIndex = 0; + break; + case 'last': this._traceIndex = this._trace.length - 1; + break; + default: + break; + } + } + + private async postMessagesToWebview(...args: string[]) { + for (const message of args) { + switch (message) { + case 'updateButtons': + const nextActive = this._traceIndex < this._trace.length - 1; + const prevActive = this._traceIndex > 0; + const firstActive = this._traceIndex > 0; + const lastActive = this._traceIndex !== this._trace.length - 1; + await this._panel!.webview.postMessage({ + command: 'updateButtons', + next: nextActive, + prev: prevActive, + first: firstActive, + last: lastActive, + }); + break; + case 'updateContent': + await this._panel!.webview.postMessage({ + command: 'updateContent', + traceComplete: this._backendTrace.complete, + traceElem: this._trace[this._traceIndex], + traceIndex: this._traceIndex, + traceLen: this._trace.length, + }); + break; + } + }; + } + + private createDecorationOptions(range: vscode.Range): vscode.DecorationOptions[] { + return [ + { + range: range, + }, + ]; + } +} diff --git a/src/programflow-visualization/main.ts b/src/programflow-visualization/main.ts new file mode 100644 index 00000000..64c18d65 --- /dev/null +++ b/src/programflow-visualization/main.ts @@ -0,0 +1,46 @@ +import * as vscode from 'vscode'; +import { startBackend } from './backend/backend'; +import * as FileHandler from './FileHandler'; +import { Md5 } from 'ts-md5'; +import { startFrontend } from './frontend/frontend'; +import { traceAlreadyExists } from './trace_cache'; + +export function getProgFlowVizCallback(context: vscode.ExtensionContext, outChannel: vscode.OutputChannel): () => Promise { + return async () => { + try { + const file = vscode.window.activeTextEditor ? + vscode.window.activeTextEditor.document.uri : + undefined; + if (!file) { + vscode.window.showWarningMessage('No file is open'); + return; + } + if (!file.fsPath.endsWith('.py')) { + vscode.window.showWarningMessage('Not a Python file'); + return; + } + vscode.window.activeTextEditor?.document.save(); + + const content = await FileHandler.getContentOf(file); + const fileHash = Md5.hashStr(content); + + let tracePort = null; + if (!(await traceAlreadyExists(context, fileHash))) { + tracePort = startBackend(context, file, outChannel); + } + + const result = await startFrontend(context, file.fsPath, fileHash, tracePort); + if (result) { + await vscode.window.showErrorMessage("Error ProgramFlow-Visualization: " + result.errorMessage); + return; + } + } catch (e: any) { + if (e instanceof Error) { + outChannel.appendLine(e.stack?.toString() ?? "Error: "); + } else { + outChannel.appendLine(e); + } + outChannel.show(true); + } + }; +} diff --git a/src/programflow-visualization/trace_cache.ts b/src/programflow-visualization/trace_cache.ts new file mode 100644 index 00000000..0cc049d8 --- /dev/null +++ b/src/programflow-visualization/trace_cache.ts @@ -0,0 +1,49 @@ +import { Variables } from './constants'; +import * as vscode from 'vscode'; +import * as tmp from 'tmp'; +import path = require('path'); +import stringify from 'stringify-json'; +import util = require('util'); +import * as FileHandler from './FileHandler'; + +export async function initTraceCache(context: vscode.ExtensionContext): Promise { + tmp.setGracefulCleanup(); + const tmpDir = tmp.dirSync({ prefix: 'ProgramFlowVisualization', unsafeCleanup: true }); + await setContextState(context, Variables.TRACE_CACHE_DIR, tmpDir.name); + + const cachedTraces: string[] = []; + await setContextState(context, Variables.CACHED_TRACES, cachedTraces); + +} + +export async function traceAlreadyExists(context: vscode.ExtensionContext, fileHash: string): Promise { + // Check if the hash is contained in cachedTraces, a list of hashes for which a trace already exists + const cachedTraces: string[] = await getContextState(context, Variables.CACHED_TRACES) ?? []; + return cachedTraces.includes(fileHash); +} + +async function getContextState(context: vscode.ExtensionContext, key: string): Promise { + return await context.workspaceState.get(key); +} + +async function setContextState(context: vscode.ExtensionContext, key: string, value: any): Promise { + return await context.workspaceState.update(key, value); +} + +async function traceCachePath(context: vscode.ExtensionContext, fileHash: string): Promise { + const cacheDir = await getContextState(context, Variables.TRACE_CACHE_DIR) ?? ""; + return path.join(cacheDir, fileHash + '.json'); +} + +export async function cacheTrace(context: vscode.ExtensionContext, fileHash: string, trace: BackendTrace) { + const path = await traceCachePath(context, fileHash); + await vscode.workspace.fs.writeFile(vscode.Uri.file(path), new util.TextEncoder().encode(stringify(trace))); + + const cachedTraces: string[] = await getContextState(context, Variables.CACHED_TRACES) ?? []; + cachedTraces.push(fileHash); +} + +export async function getTrace(context: vscode.ExtensionContext, fileHash: string): Promise { + const path = await traceCachePath(context, fileHash); + return JSON.parse(await FileHandler.getContentOf(vscode.Uri.file(path))); +} diff --git a/src/programflow-visualization/types.ts b/src/programflow-visualization/types.ts new file mode 100644 index 00000000..c1d503f1 --- /dev/null +++ b/src/programflow-visualization/types.ts @@ -0,0 +1,54 @@ +/** + * For better readable code +*/ +type Try = Success | Failure; +type Success = { result: any }; +type Failure = { errorMessage: string }; + +// State Types for the Frontend +type FrontendTrace = Array; +type FrontendTraceElem = [number, string, string, string, string]; +// ############################################################################################ +// State Types for the Backend +type PartialBackendTrace = { + trace: BackendTrace; + complete: boolean; +}; +type BackendTrace = Array; +type BackendTraceElem = { + line: number; + filePath: string, + stack: Array; + heap: Map; + stdout: string; +}; + +type Address = number; + +type Value = + | { type: 'int'; value: number } + | { type: 'float'; value: number } + | { type: 'str'; value: string } + | { type: 'none'; value: string } + | { type: 'bool'; value: string } + | { type: 'ref'; value: Address }; + +type NamedValue = Value & { + name: string; +}; + + +type StackElem = { + frameName: string; + locals: Array; +}; + +type HeapValue = + | { type: 'list'; value: Array } + | { type: 'tuple'; value: Array } + | { type: 'set'; value: Array } + | { type: 'dict'; keys: Map, value: Map } + | { type: 'type', value: string } + | { type: 'instance'; name: string, value: Map }; +// wrapper type -> frontend list elements dodge + diff --git a/src/test/runTest.ts b/src/test/runTest.ts index 1eabfa33..27b3ceb2 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -1,6 +1,6 @@ import * as path from 'path'; -import { runTests } from 'vscode-test'; +import { runTests } from '@vscode/test-electron'; async function main() { try { diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 7029e38e..73408d7d 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import * as Mocha from 'mocha'; import * as glob from 'glob'; -export function run(): Promise { +export async function run() { // Create the mocha test const mocha = new Mocha({ ui: 'tdd', @@ -11,28 +11,17 @@ export function run(): Promise { const testsRoot = path.resolve(__dirname, '..'); - 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))); - - 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); + const files = await glob.glob('**/**.test.js', { cwd: testsRoot }); + files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); + try { + // Run the mocha test + mocha.run(failures => { + if (failures > 0) { + throw new Error(`${failures} tests failed.`); } }); - }); + } catch (err) { + console.error(err); + throw err; + } }