From 08919738677e564b3ff7ca29b0eacf8bccadd850 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Wed, 20 Nov 2024 19:38:13 +0100 Subject: [PATCH 01/13] chore: correct some typings changelog --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78539deb..f2cb4fa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,10 @@ All notable changes to this project will be documented in this file. See [conven - **analyze:** `analyze code` now return a flag that indicates if errors/warnings/etc. occurs ([5125f7d](https://github.com/robotcodedev/robotcode/commit/5125f7dca21daf18f21708ab0676d8707fbb2827)) - `0`: **SUCCESS** - No issues detected. - - `1`: **ERRORS** - Critical issues found. - - `2`: **WARNINGS** - Non-critical issues detected. - - `4`: **INFORMATIONS** - General information messages. - - `8`: **HINTS** - Suggestions or improvements. + - `1`: **ERRORS** - Critical issues found. + - `2`: **WARNINGS** - Non-critical issues detected. + - `4`: **INFORMATIONS** - General information messages. + - `8`: **HINTS** - Suggestions or improvements. A return code 1 means error and 3 means there are errors and warning and so on. From 8c7212db8f9dd687c63e90197a3c0311b79923eb Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 21 Nov 2024 00:26:14 +0100 Subject: [PATCH 02/13] chore: update packages --- docs/package.json | 4 +- package-lock.json | 838 +++++++++++++++++++++++----------------------- package.json | 14 +- 3 files changed, 436 insertions(+), 420 deletions(-) diff --git a/docs/package.json b/docs/package.json index faf48427..09a85d26 100644 --- a/docs/package.json +++ b/docs/package.json @@ -13,10 +13,10 @@ "markdown-it-mathjax3": "^4.3.2", "markdown-it-task-lists": "^2.1.1", "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0", + "typescript-eslint": "^8.15.0", "vitepress": "^1.5.0", "vitepress-plugin-tabs": "^0.5.0", - "vitepress-sidebar": "^1.28.0" + "vitepress-sidebar": "^1.29.0" }, "dependencies": { "docs": "file:" diff --git a/package-lock.json b/package-lock.json index 112448d7..9b291c4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,24 +24,24 @@ "vscode-languageclient": "^9.0.1" }, "devDependencies": { - "@eslint/compat": "^1.2.2", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.14.0", + "@eslint/compat": "^1.2.3", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^9.15.0", "@types/fs-extra": "^11.0.4", - "@types/node": "^22.7.2", + "@types/node": "^22.9.1", "@types/vscode": "^1.86.0", "@vscode/test-electron": "^2.4.1", "@vscode/vsce": "^3.2.1", "esbuild": "^0.24.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "globals": "^15.12.0", - "ovsx": "^0.10.0", + "ovsx": "^0.10.1", "prettier": "^3.3.3", "ts-loader": "^9.5.1", "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0" + "typescript-eslint": "^8.15.0" }, "engines": { "vscode": "^1.86.0" @@ -57,10 +57,10 @@ "markdown-it-mathjax3": "^4.3.2", "markdown-it-task-lists": "^2.1.1", "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0", + "typescript-eslint": "^8.15.0", "vitepress": "^1.5.0", "vitepress-plugin-tabs": "^0.5.0", - "vitepress-sidebar": "^1.28.0" + "vitepress-sidebar": "^1.29.0" } }, "node_modules/@algolia/autocomplete-core": { @@ -113,41 +113,41 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.13.0.tgz", - "integrity": "sha512-6CoQjlMi1pmQYMQO8tXfuGxSPf6iKX5FP9MuMe6IWmvC81wwTvOehnwchyBl2wuPVhcw2Ar53K53mQ60DAC64g==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.15.0.tgz", + "integrity": "sha512-FaEM40iuiv1mAipYyiptP4EyxkJ8qHfowCpEeusdHUC4C7spATJYArD2rX3AxkVeREkDIgYEOuXcwKUbDCr7Nw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.13.0.tgz", - "integrity": "sha512-pS3qyXiWTwKnrt/jE79fqkNqZp7kjsFNlJDcBGkSWid74DNc6DmArlkvPqyLxnoaYGjUGACT6g56n7E3mVV2TA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.15.0.tgz", + "integrity": "sha512-lho0gTFsQDIdCwyUKTtMuf9nCLwq9jOGlLGIeQGKDxXF7HbiAysFIu5QW/iQr1LzMgDyM9NH7K98KY+BiIFriQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.13.0.tgz", - "integrity": "sha512-2SP6bGGWOTN920MLZv8s7yIR3OqY03vEe4U+vb2MGdL8a/8EQznF3L/nTC/rGf/hvEfZlX2tGFxPJaF2waravg==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.15.0.tgz", + "integrity": "sha512-IofrVh213VLsDkPoSKMeM9Dshrv28jhDlBDLRcVJQvlL8pzue7PEB1EZ4UoJFYS3NSn7JOcJ/V+olRQzXlJj1w==", "dev": true, "license": "MIT", "engines": { @@ -155,151 +155,151 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.13.0.tgz", - "integrity": "sha512-ldHTe+LVgC6L4Wr6doAQQ7Ku0jAdhaaPg1T+IHzmmiRZb2Uq5OsjW2yC65JifOmzPCiMkIZE2mGRpWgkn5ktlw==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.15.0.tgz", + "integrity": "sha512-bDDEQGfFidDi0UQUCbxXOCdphbVAgbVmxvaV75cypBTQkJ+ABx/Npw7LkFGw1FsoVrttlrrQbwjvUB6mLVKs/w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.13.0.tgz", - "integrity": "sha512-RnCfOSN4OUJDuMNHFca2M8lY64Tmw0kQOZikge4TknTqHmlbKJb8IbJE7Rol79Z80W2Y+B1ydcjV7DPje4GMRA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.15.0.tgz", + "integrity": "sha512-LfaZqLUWxdYFq44QrasCDED5bSYOswpQjSiIL7Q5fYlefAAUO95PzBPKCfUhSwhb4rKxigHfDkd81AvEicIEoA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.13.0.tgz", - "integrity": "sha512-pYo0jbLUtPDN1r341UHTaF2fgN5rbaZfDZqjPRKPM+FRlRmxFxqFQm1UUfpkSUWYGn7lECwDpbKYiKUf81MTwA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.15.0.tgz", + "integrity": "sha512-wu8GVluiZ5+il8WIRsGKu8VxMK9dAlr225h878GGtpTL6VBvwyJvAyLdZsfFIpY0iN++jiNb31q2C1PlPL+n/A==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.13.0.tgz", - "integrity": "sha512-s2ge3uZ6Zg2sPSFibqijgEYsuorxcc8KVHg3I95nOPHvFHdnBtSHymhZvq4sp/fu8ijt/Y8jLwkuqm5myn+2Sg==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.15.0.tgz", + "integrity": "sha512-Z32gEMrRRpEta5UqVQA612sLdoqY3AovvUPClDfMxYrbdDAebmGDVPtSogUba1FZ4pP5dx20D3OV3reogLKsRA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.13.0.tgz", - "integrity": "sha512-fm5LEOe4FPDOc1D+M9stEs8hfcdmbdD+pt9og5shql6ueTZJANDbFoQhDOpiPJizR/ps1GwmjkWfUEywx3sV+Q==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.15.0.tgz", + "integrity": "sha512-MkqkAxBQxtQ5if/EX2IPqFA7LothghVyvPoRNA/meS2AW2qkHwcxjuiBxv4H6mnAVEPfJlhu9rkdVz9LgCBgJg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.13.0.tgz", - "integrity": "sha512-e8Hshlnm2G5fapyUgWTBwhJ22yXcnLtPC4LWZKx7KOvv35GcdoHtlUBX94I/sWCJLraUr65JvR8qOo3LXC43dg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.15.0.tgz", + "integrity": "sha512-QPrFnnGLMMdRa8t/4bs7XilPYnoUXDY8PMQJ1sf9ZFwhUysYYhQNX34/enoO0LBjpoOY6rLpha39YQEFbzgKyQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.13.0.tgz", - "integrity": "sha512-53/wW96oaj1FKMzGdFcZ/epygfTppLDUvgI1thLkd475EtVZCH3ZZVUNCEvf1AtnNyH1RnItkFzX8ayWCpx2PQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.15.0.tgz", + "integrity": "sha512-5eupMwSqMLDObgSMF0XG958zR6GJP3f7jHDQ3/WlzCM9/YIJiWIUoJFGsko9GYsA5xbLDHE/PhWtq4chcCdaGQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-common": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.13.0.tgz", - "integrity": "sha512-NV6oSCt5lFuzfsVQoSBpewEWf/h4ySr7pv2bfwu9yF/jc/g39pig8+YpuqsxlRWBm/lTGVA2V0Ai9ySwrNumIA==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.15.0.tgz", + "integrity": "sha512-Po/GNib6QKruC3XE+WKP1HwVSfCDaZcXu48kD+gwmtDlqHWKc7Bq9lrS0sNZ456rfCKhXksOmMfUs4wRM/Y96w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0" + "@algolia/client-common": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.13.0.tgz", - "integrity": "sha512-094bK4rumf+rXJazxv3mq6eKRM0ep5AxIo8T0YmOdldswQt79apeufFiPLN19nHEWH22xR2FelimD+T/wRSP+Q==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.15.0.tgz", + "integrity": "sha512-rOZ+c0P7ajmccAvpeeNrUmEKoliYFL8aOR5qGW5pFq3oj3Iept7Y5mEtEsOBYsRt6qLnaXn4zUKf+N8nvJpcIw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0" + "@algolia/client-common": "5.15.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.13.0.tgz", - "integrity": "sha512-JY5xhEYMgki53Wm+A6R2jUpOUdD0zZnBq+PC5R1TGMNOYL1s6JjDrJeMsvaI2YWxYMUSoCnRoltN/yf9RI8n3A==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.15.0.tgz", + "integrity": "sha512-b1jTpbFf9LnQHEJP5ddDJKE2sAlhYd7EVSOWgzo/27n/SfCoHfqD0VWntnWYD83PnOKvfe8auZ2+xCb0TXotrQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.13.0" + "@algolia/client-common": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -462,9 +462,9 @@ } }, "node_modules/@azure/msal-node": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.1.tgz", - "integrity": "sha512-1NEFpTmMMT2A7RnZuvRl/hUmJU+GLPjh+ShyIqPktG2PvSd2yvPnzGd/BxIBAAvJG5nr9lH4oYcQXepDbaE7fg==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.2.tgz", + "integrity": "sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1028,9 +1028,9 @@ } }, "node_modules/@eslint/compat": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.2.tgz", - "integrity": "sha512-jhgiIrsw+tRfcBQ4BFl2C3vCrIUw2trCY0cnDvGZpwTtKCEDmZhAtMfrEUP/KpnwM6PrO0T+Ltm+ccW74olG3Q==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.3.tgz", + "integrity": "sha512-wlZhwlDFxkxIZ571aH0FoK4h4Vwx7P3HJx62Gp8hTc10bfpwT2x0nULuAHmQSJBOWPgPeVf+9YtnD4j50zVHmA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1046,9 +1046,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1061,9 +1061,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1071,9 +1071,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, "license": "MIT", "dependencies": { @@ -1108,9 +1108,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", + "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", "dev": true, "license": "MIT", "engines": { @@ -1128,9 +1128,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", - "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1207,9 +1207,9 @@ } }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.11.tgz", - "integrity": "sha512-AHCGDtBRqP+JzAbBzgO8uN/08CXxEmuaC6lQQZ3b5burKhRU12AJnJczwbUw2K5Mb/U85EpSUNhYMG3F28b8NA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.12.tgz", + "integrity": "sha512-lRNORrIdeLStShxAjN6FgXE1iMkaAgiAHZdP0P0GZecX91FVYW58uZnRSlXLlSx5cxMoELulkAAixybPA2g52g==", "dev": true, "license": "CC0-1.0", "dependencies": { @@ -1373,9 +1373,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.25.0.tgz", - "integrity": "sha512-CC/ZqFZwlAIbU1wUPisHyV/XRc5RydFrNLtgl3dGYskdwPZdt4HERtKm50a/+DtTlKeCq9IXFEWR+P6blwjqBA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.3.tgz", + "integrity": "sha512-EzxVSkIvCFxUd4Mgm4xR9YXrcp976qVaHnqom/Tgm+vU79k4vV4eYTjmRvGfeoW8m9LVcsAy/lGjcgVegKEhLQ==", "cpu": [ "arm" ], @@ -1387,9 +1387,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.25.0.tgz", - "integrity": "sha512-/Y76tmLGUJqVBXXCfVS8Q8FJqYGhgH4wl4qTA24E9v/IJM0XvJCGQVSW1QZ4J+VURO9h8YCa28sTFacZXwK7Rg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.3.tgz", + "integrity": "sha512-LJc5pDf1wjlt9o/Giaw9Ofl+k/vLUaYsE2zeQGH85giX2F+wn/Cg8b3c5CDP3qmVmeO5NzwVUzQQxwZvC2eQKw==", "cpu": [ "arm64" ], @@ -1401,9 +1401,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.25.0.tgz", - "integrity": "sha512-YVT6L3UrKTlC0FpCZd0MGA7NVdp7YNaEqkENbWQ7AOVOqd/7VzyHpgIpc1mIaxRAo1ZsJRH45fq8j4N63I/vvg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.3.tgz", + "integrity": "sha512-OuRysZ1Mt7wpWJ+aYKblVbJWtVn3Cy52h8nLuNSzTqSesYw1EuN6wKp5NW/4eSre3mp12gqFRXOKTcN3AI3LqA==", "cpu": [ "arm64" ], @@ -1415,9 +1415,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.25.0.tgz", - "integrity": "sha512-ZRL+gexs3+ZmmWmGKEU43Bdn67kWnMeWXLFhcVv5Un8FQcx38yulHBA7XR2+KQdYIOtD0yZDWBCudmfj6lQJoA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.3.tgz", + "integrity": "sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==", "cpu": [ "x64" ], @@ -1429,9 +1429,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.25.0.tgz", - "integrity": "sha512-xpEIXhiP27EAylEpreCozozsxWQ2TJbOLSivGfXhU4G1TBVEYtUPi2pOZBnvGXHyOdLAUUhPnJzH3ah5cqF01g==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.3.tgz", + "integrity": "sha512-58E0tIcwZ+12nK1WiLzHOD8I0d0kdrY/+o7yFVPRHuVGY3twBwzwDdTIBGRxLmyjciMYl1B/U515GJy+yn46qw==", "cpu": [ "arm64" ], @@ -1443,9 +1443,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.25.0.tgz", - "integrity": "sha512-sC5FsmZGlJv5dOcURrsnIK7ngc3Kirnx3as2XU9uER+zjfyqIjdcMVgzy4cOawhsssqzoAX19qmxgJ8a14Qrqw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.3.tgz", + "integrity": "sha512-78fohrpcVwTLxg1ZzBMlwEimoAJmY6B+5TsyAZ3Vok7YabRBUvjYTsRXPTjGEvv/mfgVBepbW28OlMEz4w8wGA==", "cpu": [ "x64" ], @@ -1457,9 +1457,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.25.0.tgz", - "integrity": "sha512-uD/dbLSs1BEPzg564TpRAQ/YvTnCds2XxyOndAO8nJhaQcqQGFgv/DAVko/ZHap3boCvxnzYMa3mTkV/B/3SWA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.3.tgz", + "integrity": "sha512-h2Ay79YFXyQi+QZKo3ISZDyKaVD7uUvukEHTOft7kh00WF9mxAaxZsNs3o/eukbeKuH35jBvQqrT61fzKfAB/Q==", "cpu": [ "arm" ], @@ -1471,9 +1471,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.25.0.tgz", - "integrity": "sha512-ZVt/XkrDlQWegDWrwyC3l0OfAF7yeJUF4fq5RMS07YM72BlSfn2fQQ6lPyBNjt+YbczMguPiJoCfaQC2dnflpQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.3.tgz", + "integrity": "sha512-Sv2GWmrJfRY57urktVLQ0VKZjNZGogVtASAgosDZ1aUB+ykPxSi3X1nWORL5Jk0sTIIwQiPH7iE3BMi9zGWfkg==", "cpu": [ "arm" ], @@ -1485,9 +1485,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.25.0.tgz", - "integrity": "sha512-qboZ+T0gHAW2kkSDPHxu7quaFaaBlynODXpBVnPxUgvWYaE84xgCKAPEYE+fSMd3Zv5PyFZR+L0tCdYCMAtG0A==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.3.tgz", + "integrity": "sha512-FPoJBLsPW2bDNWjSrwNuTPUt30VnfM8GPGRoLCYKZpPx0xiIEdFip3dH6CqgoT0RnoGXptaNziM0WlKgBc+OWQ==", "cpu": [ "arm64" ], @@ -1499,9 +1499,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.25.0.tgz", - "integrity": "sha512-ndWTSEmAaKr88dBuogGH2NZaxe7u2rDoArsejNslugHZ+r44NfWiwjzizVS1nUOHo+n1Z6qV3X60rqE/HlISgw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.3.tgz", + "integrity": "sha512-TKxiOvBorYq4sUpA0JT+Fkh+l+G9DScnG5Dqx7wiiqVMiRSkzTclP35pE6eQQYjP4Gc8yEkJGea6rz4qyWhp3g==", "cpu": [ "arm64" ], @@ -1513,9 +1513,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.25.0.tgz", - "integrity": "sha512-BVSQvVa2v5hKwJSy6X7W1fjDex6yZnNKy3Kx1JGimccHft6HV0THTwNtC2zawtNXKUu+S5CjXslilYdKBAadzA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.3.tgz", + "integrity": "sha512-v2M/mPvVUKVOKITa0oCFksnQQ/TqGrT+yD0184/cWHIu0LoIuYHwox0Pm3ccXEz8cEQDLk6FPKd1CCm+PlsISw==", "cpu": [ "ppc64" ], @@ -1527,9 +1527,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.25.0.tgz", - "integrity": "sha512-G4hTREQrIdeV0PE2JruzI+vXdRnaK1pg64hemHq2v5fhv8C7WjVaeXc9P5i4Q5UC06d/L+zA0mszYIKl+wY8oA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.3.tgz", + "integrity": "sha512-LdrI4Yocb1a/tFVkzmOE5WyYRgEBOyEhWYJe4gsDWDiwnjYKjNs7PS6SGlTDB7maOHF4kxevsuNBl2iOcj3b4A==", "cpu": [ "riscv64" ], @@ -1541,9 +1541,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.25.0.tgz", - "integrity": "sha512-9T/w0kQ+upxdkFL9zPVB6zy9vWW1deA3g8IauJxojN4bnz5FwSsUAD034KpXIVX5j5p/rn6XqumBMxfRkcHapQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.3.tgz", + "integrity": "sha512-d4wVu6SXij/jyiwPvI6C4KxdGzuZOvJ6y9VfrcleHTwo68fl8vZC5ZYHsCVPUi4tndCfMlFniWgwonQ5CUpQcA==", "cpu": [ "s390x" ], @@ -1555,9 +1555,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.25.0.tgz", - "integrity": "sha512-ThcnU0EcMDn+J4B9LD++OgBYxZusuA7iemIIiz5yzEcFg04VZFzdFjuwPdlURmYPZw+fgVrFzj4CA64jSTG4Ig==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.3.tgz", + "integrity": "sha512-/6bn6pp1fsCGEY5n3yajmzZQAh+mW4QPItbiWxs69zskBzJuheb3tNynEjL+mKOsUSFK11X4LYF2BwwXnzWleA==", "cpu": [ "x64" ], @@ -1569,9 +1569,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.25.0.tgz", - "integrity": "sha512-zx71aY2oQxGxAT1JShfhNG79PnjYhMC6voAjzpu/xmMjDnKNf6Nl/xv7YaB/9SIa9jDYf8RBPWEnjcdlhlv1rQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.3.tgz", + "integrity": "sha512-nBXOfJds8OzUT1qUreT/en3eyOXd2EH5b0wr2bVB5999qHdGKkzGzIyKYaKj02lXk6wpN71ltLIaQpu58YFBoQ==", "cpu": [ "x64" ], @@ -1583,9 +1583,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.25.0.tgz", - "integrity": "sha512-JT8tcjNocMs4CylWY/CxVLnv8e1lE7ff1fi6kbGocWwxDq9pj30IJ28Peb+Y8yiPNSF28oad42ApJB8oUkwGww==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.3.tgz", + "integrity": "sha512-ogfbEVQgIZOz5WPWXF2HVb6En+kWzScuxJo/WdQTqEgeyGkaa2ui5sQav9Zkr7bnNCLK48uxmmK0TySm22eiuw==", "cpu": [ "arm64" ], @@ -1597,9 +1597,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.25.0.tgz", - "integrity": "sha512-dRLjLsO3dNOfSN6tjyVlG+Msm4IiZnGkuZ7G5NmpzwF9oOc582FZG05+UdfTbz5Jd4buK/wMb6UeHFhG18+OEg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.3.tgz", + "integrity": "sha512-ecE36ZBMLINqiTtSNQ1vzWc5pXLQHlf/oqGp/bSbi7iedcjcNb6QbCBNG73Euyy2C+l/fn8qKWEwxr+0SSfs3w==", "cpu": [ "ia32" ], @@ -1611,9 +1611,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.25.0.tgz", - "integrity": "sha512-/RqrIFtLB926frMhZD0a5oDa4eFIbyNEwLLloMTEjmqfwZWXywwVVOVmwTsuyhC9HKkVEZcOOi+KV4U9wmOdlg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.3.tgz", + "integrity": "sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==", "cpu": [ "x64" ], @@ -1625,57 +1625,57 @@ ] }, "node_modules/@shikijs/core": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.22.2.tgz", - "integrity": "sha512-bvIQcd8BEeR1yFvOYv6HDiyta2FFVePbzeowf5pPS1avczrPK+cjmaxxh0nx5QzbON7+Sv0sQfQVciO7bN72sg==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.23.1.tgz", + "integrity": "sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/engine-javascript": "1.22.2", - "@shikijs/engine-oniguruma": "1.22.2", - "@shikijs/types": "1.22.2", + "@shikijs/engine-javascript": "1.23.1", + "@shikijs/engine-oniguruma": "1.23.1", + "@shikijs/types": "1.23.1", "@shikijs/vscode-textmate": "^9.3.0", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.3" } }, "node_modules/@shikijs/engine-javascript": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.22.2.tgz", - "integrity": "sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.23.1.tgz", + "integrity": "sha512-i/LdEwT5k3FVu07SiApRFwRcSJs5QM9+tod5vYCPig1Ywi8GR30zcujbxGQFJHwYD7A5BUqagi8o5KS+LEVgBg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "1.22.2", + "@shikijs/types": "1.23.1", "@shikijs/vscode-textmate": "^9.3.0", - "oniguruma-to-js": "0.4.3" + "oniguruma-to-es": "0.4.1" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.2.tgz", - "integrity": "sha512-GIZPAGzQOy56mGvWMoZRPggn0dTlBf1gutV5TdceLCZlFNqWmuc7u+CzD0Gd9vQUTgLbrt0KLzz6FNprqYAxlA==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.23.1.tgz", + "integrity": "sha512-KQ+lgeJJ5m2ISbUZudLR1qHeH3MnSs2mjFg7bnencgs5jDVPeJ2NVDJ3N5ZHbcTsOIh0qIueyAJnwg7lg7kwXQ==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "1.22.2", + "@shikijs/types": "1.23.1", "@shikijs/vscode-textmate": "^9.3.0" } }, "node_modules/@shikijs/transformers": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.22.2.tgz", - "integrity": "sha512-8f78OiBa6pZDoZ53lYTmuvpFPlWtevn23bzG+azpPVvZg7ITax57o/K3TC91eYL3OMJOO0onPbgnQyZjRos8XQ==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.23.1.tgz", + "integrity": "sha512-yQ2Cn0M9i46p30KwbyIzLvKDk+dQNU+lj88RGO0XEj54Hn4Cof1bZoDb9xBRWxFE4R8nmK63w7oHnJwvOtt0NQ==", "dev": true, "license": "MIT", "dependencies": { - "shiki": "1.22.2" + "shiki": "1.23.1" } }, "node_modules/@shikijs/types": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.22.2.tgz", - "integrity": "sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.23.1.tgz", + "integrity": "sha512-98A5hGyEhzzAgQh2dAeHKrWW4HfCMeoFER2z16p5eJ+vmPeF6lZ/elEne6/UCU551F/WqkopqRsr1l2Yu6+A0g==", "dev": true, "license": "MIT", "dependencies": { @@ -1795,9 +1795,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "version": "22.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz", + "integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==", "dev": true, "license": "MIT", "dependencies": { @@ -1826,17 +1826,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", - "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz", + "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/type-utils": "8.14.0", - "@typescript-eslint/utils": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/type-utils": "8.15.0", + "@typescript-eslint/utils": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1860,16 +1860,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", - "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", + "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "debug": "^4.3.4" }, "engines": { @@ -1889,14 +1889,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", - "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz", + "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0" + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1907,14 +1907,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", - "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz", + "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/utils": "8.15.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1925,6 +1925,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -1932,9 +1935,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", - "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz", + "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==", "dev": true, "license": "MIT", "engines": { @@ -1946,14 +1949,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", - "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz", + "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2001,16 +2004,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", - "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz", + "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0" + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2021,17 +2024,22 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", - "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz", + "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.15.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2041,19 +2049,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/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, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -2062,9 +2057,9 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-vue": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.5.tgz", - "integrity": "sha512-dlnib73G05CDBAUR/YpuZcQQ47fpjihnnNouAAqN62z+oqSsWJ+kh52GRzIxpkgFG3q11eXK7Di7RMmoCwISZA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", + "integrity": "sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==", "dev": true, "license": "MIT", "engines": { @@ -2290,57 +2285,57 @@ ] }, "node_modules/@vue/compiler-core": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz", - "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.12", + "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", - "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", - "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", - "@vue/compiler-core": "3.5.12", - "@vue/compiler-dom": "3.5.12", - "@vue/compiler-ssr": "3.5.12", - "@vue/shared": "3.5.12", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", - "postcss": "^8.4.47", + "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", - "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/devtools-api": { @@ -2380,57 +2375,57 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.12.tgz", - "integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.12" + "@vue/shared": "3.5.13" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.12.tgz", - "integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", - "integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.12", - "@vue/runtime-core": "3.5.12", - "@vue/shared": "3.5.12", + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.12.tgz", - "integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" }, "peerDependencies": { - "vue": "3.5.12" + "vue": "3.5.13" } }, "node_modules/@vue/shared": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz", - "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", "dev": true, "license": "MIT" }, @@ -2878,25 +2873,25 @@ } }, "node_modules/algoliasearch": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.13.0.tgz", - "integrity": "sha512-04lyQX3Ev/oLYQx+aagamQDXvkUUfX1mwrLrus15+9fNaYj28GDxxEzbwaRfvmHFcZyoxvup7mMtDTTw8SrTEQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.15.0.tgz", + "integrity": "sha512-Yf3Swz1s63hjvBVZ/9f2P1Uu48GjmjCN+Esxb6MAONMGtZB1fRX8/S1AhUTtsuTlcGovbYLxpHgc7wEzstDZBw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-abtesting": "5.13.0", - "@algolia/client-analytics": "5.13.0", - "@algolia/client-common": "5.13.0", - "@algolia/client-insights": "5.13.0", - "@algolia/client-personalization": "5.13.0", - "@algolia/client-query-suggestions": "5.13.0", - "@algolia/client-search": "5.13.0", - "@algolia/ingestion": "1.13.0", - "@algolia/monitoring": "1.13.0", - "@algolia/recommend": "5.13.0", - "@algolia/requester-browser-xhr": "5.13.0", - "@algolia/requester-fetch": "5.13.0", - "@algolia/requester-node-http": "5.13.0" + "@algolia/client-abtesting": "5.15.0", + "@algolia/client-analytics": "5.15.0", + "@algolia/client-common": "5.15.0", + "@algolia/client-insights": "5.15.0", + "@algolia/client-personalization": "5.15.0", + "@algolia/client-query-suggestions": "5.15.0", + "@algolia/client-search": "5.15.0", + "@algolia/ingestion": "1.15.0", + "@algolia/monitoring": "1.15.0", + "@algolia/recommend": "5.15.0", + "@algolia/requester-browser-xhr": "5.15.0", + "@algolia/requester-fetch": "5.15.0", + "@algolia/requester-node-http": "5.15.0" }, "engines": { "node": ">= 14.0.0" @@ -3432,9 +3427,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", - "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -3690,9 +3685,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.57", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.57.tgz", - "integrity": "sha512-xS65H/tqgOwUBa5UmOuNSLuslDo7zho0y/lgQw35pnrqiZh7UOWHCeL/Bt6noJATbA6tpQJGCifsFsIRZj1Fqg==", + "version": "1.5.63", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", + "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", "dev": true, "license": "ISC", "peer": true @@ -3704,6 +3699,13 @@ "dev": true, "license": "MIT" }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, "node_modules/encoding-sniffer": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", @@ -3862,27 +3864,27 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", + "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.15.0", + "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.5", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -3901,8 +3903,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -4350,16 +4351,16 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true, "license": "ISC" }, "node_modules/focus-trap": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.1.tgz", - "integrity": "sha512-nB8y4nQl8PshahLpGKZOq1sb0xrMVFSn6at7u/qOsBZTlZRzaapISGENcB6mOkoezbClZyiMwEF/dGY8AZ00rA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.2.tgz", + "integrity": "sha512-9FhUxK1hVju2+AiQIDJ5Dd//9R2n2RAfJ0qfhF4IHGHgcoEUTMpbTeG/zbEuwaiYXfuAH6XE0/aCyxDdRM+W5w==", "dev": true, "license": "MIT", "dependencies": { @@ -5640,9 +5641,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.13", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", + "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", "dev": true, "license": "MIT", "dependencies": { @@ -6174,17 +6175,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/oniguruma-to-js": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz", - "integrity": "sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==", + "node_modules/oniguruma-to-es": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-0.4.1.tgz", + "integrity": "sha512-rNcEohFz095QKGRovP/yqPIKc+nP+Sjs4YTHMv33nMePGKrq/r2eu9Yh4646M5XluGJsUnmwoXuiXE69KDs+fQ==", "dev": true, "license": "MIT", "dependencies": { - "regex": "^4.3.2" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "emoji-regex-xs": "^1.0.0", + "regex": "^5.0.0", + "regex-recursion": "^4.2.1" } }, "node_modules/open": { @@ -6286,13 +6286,13 @@ } }, "node_modules/ovsx": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.0.tgz", - "integrity": "sha512-DSgNXGQ444nGKag+LZh92R/hM2PfRSu+6VKfVawoZ+JzFDiGX8yhMkAuyVlHrlxLCpfQOsqs80GcHje/h2SpmA==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.1.tgz", + "integrity": "sha512-8i7+MJMMeq73m1zPEIClSFe17SNuuzU5br7G77ZIfOC24elB4pGQs0N1qRd+gnnbyhL5Qu96G21nFOVOBa2OBg==", "dev": true, "license": "EPL-2.0", "dependencies": { - "@vscode/vsce": "^3.1.0", + "@vscode/vsce": "^3.2.1", "commander": "^6.2.1", "follow-redirects": "^1.14.6", "is-ci": "^2.0.0", @@ -6680,9 +6680,9 @@ } }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", + "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6792,9 +6792,29 @@ "license": "MIT" }, "node_modules/regex": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/regex/-/regex-4.4.0.tgz", - "integrity": "sha512-uCUSuobNVeqUupowbdZub6ggI5/JZkYyJdDogddJr60L764oxC2pMZov1fQ3wM9bdyzUILDG+Sqx6NAKAz9rKQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/regex/-/regex-5.0.2.tgz", + "integrity": "sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-4.2.1.tgz", + "integrity": "sha512-QHNZyZAeKdndD1G3bKAbBEKOSSK4KOHQrAJ01N1LJeb0SoH4DJIeFhp0uUpETgONifS4+P3sOgoA1dhzgrQvhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", "dev": true, "license": "MIT" }, @@ -6855,9 +6875,9 @@ "link": true }, "node_modules/rollup": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz", - "integrity": "sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.3.tgz", + "integrity": "sha512-SLsCOnlmGt9VoZ9Ek8yBK8tAdmPHeppkw+Xa7yDlCEhDTvwYei03JlWo1fdc7YTfLZ4tD8riJCUyAgTbszk1fQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6871,24 +6891,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.25.0", - "@rollup/rollup-android-arm64": "4.25.0", - "@rollup/rollup-darwin-arm64": "4.25.0", - "@rollup/rollup-darwin-x64": "4.25.0", - "@rollup/rollup-freebsd-arm64": "4.25.0", - "@rollup/rollup-freebsd-x64": "4.25.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.25.0", - "@rollup/rollup-linux-arm-musleabihf": "4.25.0", - "@rollup/rollup-linux-arm64-gnu": "4.25.0", - "@rollup/rollup-linux-arm64-musl": "4.25.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.25.0", - "@rollup/rollup-linux-riscv64-gnu": "4.25.0", - "@rollup/rollup-linux-s390x-gnu": "4.25.0", - "@rollup/rollup-linux-x64-gnu": "4.25.0", - "@rollup/rollup-linux-x64-musl": "4.25.0", - "@rollup/rollup-win32-arm64-msvc": "4.25.0", - "@rollup/rollup-win32-ia32-msvc": "4.25.0", - "@rollup/rollup-win32-x64-msvc": "4.25.0", + "@rollup/rollup-android-arm-eabi": "4.27.3", + "@rollup/rollup-android-arm64": "4.27.3", + "@rollup/rollup-darwin-arm64": "4.27.3", + "@rollup/rollup-darwin-x64": "4.27.3", + "@rollup/rollup-freebsd-arm64": "4.27.3", + "@rollup/rollup-freebsd-x64": "4.27.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.3", + "@rollup/rollup-linux-arm-musleabihf": "4.27.3", + "@rollup/rollup-linux-arm64-gnu": "4.27.3", + "@rollup/rollup-linux-arm64-musl": "4.27.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.3", + "@rollup/rollup-linux-riscv64-gnu": "4.27.3", + "@rollup/rollup-linux-s390x-gnu": "4.27.3", + "@rollup/rollup-linux-x64-gnu": "4.27.3", + "@rollup/rollup-linux-x64-musl": "4.27.3", + "@rollup/rollup-win32-arm64-msvc": "4.27.3", + "@rollup/rollup-win32-ia32-msvc": "4.27.3", + "@rollup/rollup-win32-x64-msvc": "4.27.3", "fsevents": "~2.3.2" } }, @@ -6972,9 +6992,9 @@ } }, "node_modules/search-insights": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.2.tgz", - "integrity": "sha512-zFNpOpUO+tY2D85KrxJ+aqwnIfdEGi06UH2+xEb+Bp9Mwznmauqc9djbnBibJO5mpfUPPa8st6Sx65+vbeO45g==", + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", "dev": true, "license": "MIT", "peer": true @@ -7065,16 +7085,16 @@ } }, "node_modules/shiki": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.22.2.tgz", - "integrity": "sha512-3IZau0NdGKXhH2bBlUk4w1IHNxPh6A5B2sUpyY+8utLu2j/h1QpFkAaUA1bAMxOWWGtTWcAh531vnS4NJKS/lA==", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.23.1.tgz", + "integrity": "sha512-8kxV9TH4pXgdKGxNOkrSMydn1Xf6It8lsle0fiqxf7a1149K1WGtdOu3Zb91T5r1JpvRPxqxU3C2XdZZXQnrig==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/core": "1.22.2", - "@shikijs/engine-javascript": "1.22.2", - "@shikijs/engine-oniguruma": "1.22.2", - "@shikijs/types": "1.22.2", + "@shikijs/core": "1.23.1", + "@shikijs/engine-javascript": "1.23.1", + "@shikijs/engine-oniguruma": "1.23.1", + "@shikijs/types": "1.23.1", "@shikijs/vscode-textmate": "^9.3.0", "@types/hast": "^3.0.4" } @@ -7663,13 +7683,6 @@ "license": "MIT", "peer": true }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "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", @@ -7892,15 +7905,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.14.0.tgz", - "integrity": "sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.15.0.tgz", + "integrity": "sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.14.0", - "@typescript-eslint/parser": "8.14.0", - "@typescript-eslint/utils": "8.14.0" + "@typescript-eslint/eslint-plugin": "8.15.0", + "@typescript-eslint/parser": "8.15.0", + "@typescript-eslint/utils": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7909,6 +7922,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -7930,9 +7946,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "6.20.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.20.1.tgz", - "integrity": "sha512-AjQF1QsmqfJys+LXfGTNum+qw4S88CojRInG/6t31W/1fk6G59s92bnAvGz5Cmur+kQv2SURXEvvudLmbrE8QA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz", + "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==", "dev": true, "license": "MIT", "engines": { @@ -8839,17 +8855,17 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.12.tgz", - "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.12", - "@vue/compiler-sfc": "3.5.12", - "@vue/runtime-dom": "3.5.12", - "@vue/server-renderer": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index 92fa9a51..07f686dc 100644 --- a/package.json +++ b/package.json @@ -1681,24 +1681,24 @@ "vscode-languageclient": "^9.0.1" }, "devDependencies": { - "@eslint/compat": "^1.2.2", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.14.0", + "@eslint/compat": "^1.2.3", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^9.15.0", "@types/fs-extra": "^11.0.4", - "@types/node": "^22.7.2", + "@types/node": "^22.9.1", "@types/vscode": "^1.86.0", "@vscode/test-electron": "^2.4.1", "@vscode/vsce": "^3.2.1", "esbuild": "^0.24.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "globals": "^15.12.0", - "ovsx": "^0.10.0", + "ovsx": "^0.10.1", "prettier": "^3.3.3", "ts-loader": "^9.5.1", "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0" + "typescript-eslint": "^8.15.0" }, "workspaces": [ "docs" From c5f766f036e49153f318e91ddefb68c975668669 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 21 Nov 2024 11:15:43 +0100 Subject: [PATCH 03/13] feat(analyzer): add error codes `VariableNotReplaced` and `EnvironmentVariableNotReplaced` for variables not found/replaced in documentation, tags, and metadata --- .../src/robotcode/robot/diagnostics/errors.py | 2 ++ .../robot/diagnostics/namespace_analyzer.py | 20 +++++++++++++++---- pyproject.toml | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/robot/src/robotcode/robot/diagnostics/errors.py b/packages/robot/src/robotcode/robot/diagnostics/errors.py index c6462caf..85b99119 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/errors.py +++ b/packages/robot/src/robotcode/robot/diagnostics/errors.py @@ -6,7 +6,9 @@ @final class Error: VARIABLE_NOT_FOUND = "VariableNotFound" + VARIABLE_NOT_REPLACED = "VariableNotReplaced" ENVIRONMENT_VARIABLE_NOT_FOUND = "EnvironmentVariableNotFound" + ENVIRONMENT_VARIABLE_NOT_REPLACED = "EnvironmentVariableNotReplaced" KEYWORD_NOT_FOUND = "KeywordNotFound" LIBRARY_CONTAINS_NO_KEYWORDS = "LibraryContainsNoKeywords" POSSIBLE_CIRCULAR_IMPORT = "PossibleCircularImport" diff --git a/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py b/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py index 854ef31e..aa66fd83 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py +++ b/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py @@ -480,9 +480,13 @@ def _handle_find_variable_result( if var.type == VariableDefinitionType.VARIABLE_NOT_FOUND: self._append_diagnostics( range=range_from_token(var_token), - message=f"Variable '{var.name}' not found.", + message=( + f"Variable '{var.name}' not replaced." + if severity == DiagnosticSeverity.HINT + else f"Variable '{var.name}' not found." + ), severity=severity, - code=Error.VARIABLE_NOT_FOUND, + code=Error.VARIABLE_NOT_REPLACED if severity == DiagnosticSeverity.HINT else Error.VARIABLE_NOT_FOUND, ) else: if ( @@ -493,9 +497,17 @@ def _handle_find_variable_result( if os.environ.get(env_name, None) is None: self._append_diagnostics( range=range_from_token(var_token), - message=f"Environment variable '{var.name}' not found.", + message=( + f"Environment variable '{var.name}' not replaced." + if severity == DiagnosticSeverity.HINT + else f"Environment variable '{var.name}' not found." + ), severity=severity, - code=Error.ENVIRONMENT_VARIABLE_NOT_FOUND, + code=( + Error.ENVIRONMENT_VARIABLE_NOT_REPLACED + if severity == DiagnosticSeverity.HINT + else Error.ENVIRONMENT_VARIABLE_NOT_FOUND + ), ) if var.type == VariableDefinitionType.ENVIRONMENT_VARIABLE: diff --git a/pyproject.toml b/pyproject.toml index 1de83170..1413fcbe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -262,6 +262,8 @@ mypy_path = [ "packages/robot/src", "packages/runner/src", "packages/analyze/src", + "packages/repl/src", + "packages/repl_server/src", ] # allow_untyped_calls = true From 18b6cb878e893b32ce26b16c3de0c6e628367fde Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 21 Nov 2024 11:34:21 +0100 Subject: [PATCH 04/13] fix(analyze): corrected statistics about analyzed files --- packages/analyze/src/robotcode/analyze/cli.py | 71 ++++++++++++------- .../src/robotcode/analyze/code_analyzer.py | 12 ++-- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/packages/analyze/src/robotcode/analyze/cli.py b/packages/analyze/src/robotcode/analyze/cli.py index daf4218d..cdc6acea 100644 --- a/packages/analyze/src/robotcode/analyze/cli.py +++ b/packages/analyze/src/robotcode/analyze/cli.py @@ -1,7 +1,7 @@ from enum import Flag from pathlib import Path from textwrap import indent -from typing import List, Optional, Set, Tuple +from typing import List, Optional, Set, Tuple, Union import click @@ -56,16 +56,49 @@ class ReturnCode(Flag): class Statistic: def __init__(self) -> None: - self.folders: Set[WorkspaceFolder] = set() - self.files: Set[TextDocument] = set() - self.errors = 0 - self.warnings = 0 - self.infos = 0 - self.hints = 0 + self._folders: Set[WorkspaceFolder] = set() + self._files: Set[TextDocument] = set() + self._diagnostics: List[Union[DocumentDiagnosticReport, FolderDiagnosticReport]] = [] + + @property + def errors(self) -> int: + return sum( + len([i for i in e.items if i.severity == DiagnosticSeverity.ERROR]) for e in self._diagnostics if e.items + ) + + @property + def warnings(self) -> int: + return sum( + len([i for i in e.items if i.severity == DiagnosticSeverity.WARNING]) for e in self._diagnostics if e.items + ) + + @property + def infos(self) -> int: + return sum( + len([i for i in e.items if i.severity == DiagnosticSeverity.INFORMATION]) + for e in self._diagnostics + if e.items + ) + + @property + def hints(self) -> int: + return sum( + len([i for i in e.items if i.severity == DiagnosticSeverity.HINT]) for e in self._diagnostics if e.items + ) + + def add_diagnostics_report( + self, diagnostics_report: Union[DocumentDiagnosticReport, FolderDiagnosticReport] + ) -> None: + self._diagnostics.append(diagnostics_report) + + if isinstance(diagnostics_report, FolderDiagnosticReport): + self._folders.add(diagnostics_report.folder) + elif isinstance(diagnostics_report, DocumentDiagnosticReport): + self._files.add(diagnostics_report.document) def __str__(self) -> str: return ( - f"Files: {len(self.files)}, Errors: {self.errors}, Warnings: {self.warnings}, " + f"Files: {len(self._files)}, Errors: {self.errors}, Warnings: {self.warnings}, " f"Infos: {self.infos}, Hints: {self.hints}" ) @@ -192,7 +225,6 @@ def code( The return code is a bitwise combination of the following values: - \b - `0`: **SUCCESS** - No issues detected. - `1`: **ERRORS** - Critical issues found. - `2`: **WARNINGS** - Non-critical issues detected. @@ -284,20 +316,17 @@ def code( robot_profile=robot_profile, root_folder=root_folder, ).run(paths=paths, filter=filter): - if isinstance(e, FolderDiagnosticReport): - statistics.folders.add(e.folder) + statistics.add_diagnostics_report(e) + if isinstance(e, FolderDiagnosticReport): if e.items: - _print_diagnostics(app, root_folder, statistics, e.items, e.folder.uri.to_path()) - + _print_diagnostics(app, root_folder, e.items, e.folder.uri.to_path()) elif isinstance(e, DocumentDiagnosticReport): - statistics.files.add(e.document) - doc_path = ( e.document.uri.to_path().relative_to(root_folder) if root_folder else e.document.uri.to_path() ) if e.items: - _print_diagnostics(app, root_folder, statistics, e.items, doc_path) + _print_diagnostics(app, root_folder, e.items, doc_path) statistics_str = str(statistics) if statistics.errors > 0: @@ -314,7 +343,6 @@ def code( def _print_diagnostics( app: Application, root_folder: Optional[Path], - statistics: Statistic, diagnostics: List[Diagnostic], folder_path: Optional[Path], print_range: bool = True, @@ -322,15 +350,6 @@ def _print_diagnostics( for item in diagnostics: severity = item.severity if item.severity is not None else DiagnosticSeverity.ERROR - if severity == DiagnosticSeverity.ERROR: - statistics.errors += 1 - elif severity == DiagnosticSeverity.WARNING: - statistics.warnings += 1 - elif severity == DiagnosticSeverity.INFORMATION: - statistics.infos += 1 - elif severity == DiagnosticSeverity.HINT: - statistics.hints += 1 - app.echo( ( ( diff --git a/packages/analyze/src/robotcode/analyze/code_analyzer.py b/packages/analyze/src/robotcode/analyze/code_analyzer.py index a6b7201d..cbea1389 100644 --- a/packages/analyze/src/robotcode/analyze/code_analyzer.py +++ b/packages/analyze/src/robotcode/analyze/code_analyzer.py @@ -93,8 +93,8 @@ def run( self.app.error(f"Error analyzing {folder.uri.to_path()}: {item}") else: diagnostics.extend(item) - if diagnostics: - yield FolderDiagnosticReport(folder, diagnostics) + + yield FolderDiagnosticReport(folder, diagnostics) documents = self.collect_documents(folder, paths=paths, filter=filter) @@ -110,8 +110,8 @@ def run( self.app.error(f"Error analyzing {document.uri.to_path()}: {item}") else: diagnostics.extend(item) - if diagnostics: - yield DocumentDiagnosticReport(document, diagnostics) + + yield DocumentDiagnosticReport(document, diagnostics) self.app.verbose(f"Collect Diagnostics for {len(documents)} documents") for document in documents: @@ -125,8 +125,8 @@ def run( self.app.error(f"Error collecting diagnostics for {document.uri.to_path()}: {item}") else: diagnostics.extend(item) - if diagnostics: - yield DocumentDiagnosticReport(document, diagnostics) + + yield DocumentDiagnosticReport(document, diagnostics) def collect_documents( self, folder: WorkspaceFolder, paths: Iterable[Path] = {}, filter: Iterable[str] = {} From 2c8ed5662be1e8621d7d9c742275ccaf1809d06c Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Tue, 26 Nov 2024 17:22:34 +0100 Subject: [PATCH 05/13] fix(analyzer): correct handling of variables in embedded args in keyword calls closes #360 --- .../robotframework/parts/semantic_tokens.py | 10 ++++++---- .../robotcode/robot/diagnostics/namespace_analyzer.py | 7 +++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py b/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py index cf7f9c56..517ede74 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py @@ -404,7 +404,7 @@ def generate_sem_sub_tokens( ): if ( namespace.find_keyword( - token.value, + unescape(token.value), # TODO: this must be resovle possible variables raise_keyword_error=False, handle_bdd_style=False, ) @@ -458,7 +458,9 @@ def generate_sem_sub_tokens( kw_namespace: Optional[str] = None kw: str = token.value - kw_doc = namespace.find_keyword(token.value, raise_keyword_error=False) + kw_doc = namespace.find_keyword( + unescape(token.value), raise_keyword_error=False + ) # TODO: this must be resovle possible variables ( lib_entry, @@ -1121,14 +1123,14 @@ def get_tokens() -> Iterator[Tuple[Token, ast.AST]]: kw: Optional[str] = None for _, n in iter_over_keyword_names_and_owners( - ModelHelper.strip_bdd_prefix(namespace, kw_token).value + unescape(ModelHelper.strip_bdd_prefix(namespace, kw_token).value) ): if n is not None: matcher = KeywordMatcher(n) if matcher in ALL_RUN_KEYWORDS_MATCHERS: kw = n if kw: - kw_doc = namespace.find_keyword(kw_token.value) + kw_doc = namespace.find_keyword(unescape(kw_token.value)) if kw_doc is not None and kw_doc.is_any_run_keyword(): for kw_res in self.generate_run_kw_tokens( namespace, diff --git a/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py b/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py index aa66fd83..630fc16f 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py +++ b/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py @@ -584,10 +584,11 @@ def _analyze_keyword_call( analyze_run_keywords: bool = True, allow_variables: bool = False, ignore_errors_if_contains_variables: bool = False, + unescape_keyword: bool = True, ) -> Optional[KeywordDoc]: result: Optional[KeywordDoc] = None - keyword = unescape(keyword_token.value) + keyword = unescape(keyword_token.value) if unescape_keyword else keyword_token.value try: lib_entry = None @@ -1008,9 +1009,7 @@ def visit_KeywordCall(self, node: KeywordCall) -> None: # noqa: N802 self._analyze_statement_variables(node) self._analyze_keyword_call( - node, - keyword_token, - [e for e in node.get_tokens(Token.ARGUMENT)], + node, keyword_token, [e for e in node.get_tokens(Token.ARGUMENT)], unescape_keyword=False ) if not self._current_testcase_or_keyword_name: From 66a94bc993a27d8fe5cec13813e524b1099509c6 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Tue, 26 Nov 2024 20:06:20 +0100 Subject: [PATCH 06/13] fix(config): corrected handling of relative items in python path and other variables if current folder is different then root folder of the project fixes #359 --- .../src/robotcode/core/utils/contextlib.py | 44 ++++++ .../plugin/src/robotcode/plugin/__init__.py | 17 +++ .../src/robotcode/robot/config/loader.py | 3 +- .../robotcode/runner/cli/discover/discover.py | 135 +++++++++--------- .../runner/src/robotcode/runner/cli/libdoc.py | 59 ++++---- .../runner/src/robotcode/runner/cli/rebot.py | 85 ++++++----- .../runner/src/robotcode/runner/cli/robot.py | 67 +++++---- .../src/robotcode/runner/cli/testdoc.py | 58 ++++---- 8 files changed, 260 insertions(+), 208 deletions(-) create mode 100644 packages/core/src/robotcode/core/utils/contextlib.py diff --git a/packages/core/src/robotcode/core/utils/contextlib.py b/packages/core/src/robotcode/core/utils/contextlib.py new file mode 100644 index 00000000..15d83f29 --- /dev/null +++ b/packages/core/src/robotcode/core/utils/contextlib.py @@ -0,0 +1,44 @@ +import os +from contextlib import AbstractContextManager +from pathlib import Path +from typing import Any, Callable, List, Literal, Optional, Union + +from .path import same_file + + +class ChDir(AbstractContextManager[Any]): + def __init__( + self, path: "Union[str, os.PathLike[str], None]", verbose_callback: Optional[Callable[[str], None]] = None + ) -> None: + self.path = path + self._old_cwd: List[Optional[Path]] = [] + self._verbose_callback = verbose_callback + + def __enter__(self) -> Optional[Path]: + result = Path.cwd() + + if self.path is None or (self._old_cwd and same_file(self.path, Path.cwd())): + self._old_cwd.append(None) + else: + self._old_cwd.append(result) + + if self.path: + if self._verbose_callback: + self._verbose_callback(f"Changing directory to {self.path}") + + os.chdir(self.path) + + return result + + def __exit__(self, _exc_type: Any, _exc_value: Any, _traceback: Any) -> Literal[False]: + old_path = self._old_cwd.pop() + if old_path is not None: + if self._verbose_callback: + self._verbose_callback(f"Changing directory back to {old_path}") + + os.chdir(old_path) + + return False + + +chdir = ChDir diff --git a/packages/plugin/src/robotcode/plugin/__init__.py b/packages/plugin/src/robotcode/plugin/__init__.py index ca0dcd02..ad398603 100644 --- a/packages/plugin/src/robotcode/plugin/__init__.py +++ b/packages/plugin/src/robotcode/plugin/__init__.py @@ -1,5 +1,6 @@ import dataclasses import sys +from contextlib import contextmanager from dataclasses import dataclass from enum import Enum, unique from pathlib import Path @@ -9,6 +10,8 @@ AnyStr, Callable, Iterable, + Iterator, + Literal, Optional, Sequence, TypeVar, @@ -20,6 +23,7 @@ import pluggy import tomli_w +from robotcode.core.utils.contextlib import chdir from robotcode.core.utils.dataclasses import as_dict, as_json __all__ = [ @@ -292,5 +296,18 @@ def exit(self, code: int = 0) -> None: self.verbose(f"Exit with code {code}") sys.exit(code) + @contextmanager + def chdir(self, path: Union[str, Path, None]) -> Iterator[Optional[Path]]: + with chdir(path, self.verbose) as result: + yield result + + @contextmanager + def save_syspath(self) -> Iterator[Literal[None]]: + self._syspath = sys.path[:] + try: + yield None + finally: + sys.path = self._syspath + pass_application = click.make_pass_decorator(Application, ensure=True) diff --git a/packages/robot/src/robotcode/robot/config/loader.py b/packages/robot/src/robotcode/robot/config/loader.py index 830438d6..a81bda93 100644 --- a/packages/robot/src/robotcode/robot/config/loader.py +++ b/packages/robot/src/robotcode/robot/config/loader.py @@ -5,6 +5,7 @@ from typing import Any, Callable, Dict, Optional, Sequence, Tuple, Type, TypeVar, Union from robotcode.core.utils.dataclasses import from_dict +from robotcode.core.utils.path import normalized_path if sys.version_info >= (3, 11): import tomllib @@ -224,7 +225,7 @@ def find_project_root( if not sources: sources = (str(Path.cwd().absolute()),) - path_srcs = [Path(Path.cwd(), src).absolute() for src in sources] + path_srcs = [normalized_path(Path(Path.cwd(), src).absolute()) for src in sources] src_parents = [list(path.parents) + ([path] if path.is_dir() else []) for path in path_srcs] diff --git a/packages/runner/src/robotcode/runner/cli/discover/discover.py b/packages/runner/src/robotcode/runner/cli/discover/discover.py index b63adad6..9a40135b 100644 --- a/packages/runner/src/robotcode/runner/cli/discover/discover.py +++ b/packages/runner/src/robotcode/runner/cli/discover/discover.py @@ -476,81 +476,84 @@ def handle_options( ) -> Tuple[TestSuite, Collector, Optional[Dict[str, List[Diagnostic]]]]: root_folder, profile, cmd_options = handle_robot_options(app, robot_options_and_args) - diagnostics_logger = DiagnosticsLogger() - try: - _patch() + with app.chdir(root_folder) as orig_folder: - options, arguments = RobotFrameworkEx( - app, - ( - [*(app.config.default_paths if app.config.default_paths else ())] - if profile.paths is None - else profile.paths if isinstance(profile.paths, list) else [profile.paths] - ), - app.config.dry, - root_folder, - by_longname, - exclude_by_longname, - ).parse_arguments((*cmd_options, "--runemptysuite", *robot_options_and_args)) + diagnostics_logger = DiagnosticsLogger() + try: + _patch() - settings = RobotSettings(options) + options, arguments = RobotFrameworkEx( + app, + ( + [*(app.config.default_paths if app.config.default_paths else ())] + if profile.paths is None + else profile.paths if isinstance(profile.paths, list) else [profile.paths] + ), + app.config.dry, + root_folder, + orig_folder, + by_longname, + exclude_by_longname, + ).parse_arguments((*cmd_options, "--runemptysuite", *robot_options_and_args)) - if app.show_diagnostics: - LOGGER.register_console_logger(**settings.console_output_config) - else: - LOGGER.unregister_console_logger() - - LOGGER.register_logger(diagnostics_logger) - - if get_robot_version() >= (5, 0): - if settings.pythonpath: - sys.path = settings.pythonpath + sys.path - - if get_robot_version() > (6, 1): - builder = TestSuiteBuilder( - included_extensions=settings.extension, - included_files=settings.parse_include, - custom_parsers=settings.parsers, - rpa=settings.rpa, - lang=settings.languages, - allow_empty_suite=settings.run_empty_suite, - ) - elif get_robot_version() >= (6, 0): - builder = TestSuiteBuilder( - settings["SuiteNames"], - included_extensions=settings.extension, - rpa=settings.rpa, - lang=settings.languages, - allow_empty_suite=settings.run_empty_suite, - ) - else: - builder = TestSuiteBuilder( - settings["SuiteNames"], - included_extensions=settings.extension, - rpa=settings.rpa, - allow_empty_suite=settings.run_empty_suite, - ) + settings = RobotSettings(options) + + if app.show_diagnostics: + LOGGER.register_console_logger(**settings.console_output_config) + else: + LOGGER.unregister_console_logger() + + LOGGER.register_logger(diagnostics_logger) + + if get_robot_version() >= (5, 0): + if settings.pythonpath: + sys.path = settings.pythonpath + sys.path + + if get_robot_version() > (6, 1): + builder = TestSuiteBuilder( + included_extensions=settings.extension, + included_files=settings.parse_include, + custom_parsers=settings.parsers, + rpa=settings.rpa, + lang=settings.languages, + allow_empty_suite=settings.run_empty_suite, + ) + elif get_robot_version() >= (6, 0): + builder = TestSuiteBuilder( + settings["SuiteNames"], + included_extensions=settings.extension, + rpa=settings.rpa, + lang=settings.languages, + allow_empty_suite=settings.run_empty_suite, + ) + else: + builder = TestSuiteBuilder( + settings["SuiteNames"], + included_extensions=settings.extension, + rpa=settings.rpa, + allow_empty_suite=settings.run_empty_suite, + ) - suite = builder.build(*arguments) - settings.rpa = suite.rpa - if settings.pre_run_modifiers: - suite.visit(ModelModifier(settings.pre_run_modifiers, settings.run_empty_suite, LOGGER)) - suite.configure(**settings.suite_config) + suite = builder.build(*arguments) + settings.rpa = suite.rpa + if settings.pre_run_modifiers: + suite.visit(ModelModifier(settings.pre_run_modifiers, settings.run_empty_suite, LOGGER)) + suite.configure(**settings.suite_config) - collector = Collector() + collector = Collector() - suite.visit(collector) + suite.visit(collector) - return suite, collector, build_diagnostics(diagnostics_logger.messages) + return suite, collector, build_diagnostics(diagnostics_logger.messages) - except Information as err: - app.echo(str(err)) - app.exit(INFO_PRINTED) - except DataError as err: - app.error(str(err)) - app.exit(DATA_ERROR) + except Information as err: + app.echo(str(err)) + app.exit(INFO_PRINTED) + except DataError as err: + app.error(str(err)) + app.exit(DATA_ERROR) - raise UnknownError("Unexpected error happened.") + raise UnknownError("Unexpected error happened.") def print_statistics(app: Application, suite: TestSuite, collector: Collector) -> None: diff --git a/packages/runner/src/robotcode/runner/cli/libdoc.py b/packages/runner/src/robotcode/runner/cli/libdoc.py index cfc4e01c..f2a718de 100644 --- a/packages/runner/src/robotcode/runner/cli/libdoc.py +++ b/packages/runner/src/robotcode/runner/cli/libdoc.py @@ -1,6 +1,4 @@ -import os -from pathlib import Path -from typing import Any, Optional, Tuple, cast +from typing import Any, Tuple, cast import click from robot.errors import DataError, Information @@ -16,10 +14,9 @@ class LibDocEx(LibDoc): - def __init__(self, dry: bool, root_folder: Optional[Path]) -> None: + def __init__(self, dry: bool) -> None: super().__init__() self.dry = dry - self.root_folder = root_folder def parse_arguments(self, cli_args: Any) -> Any: options, arguments = super().parse_arguments(cli_args) @@ -35,9 +32,6 @@ def parse_arguments(self, cli_args: Any) -> Any: return options, arguments def main(self, arguments: Any, **options: Any) -> Any: - if self.root_folder is not None: - os.chdir(self.root_folder) - return super().main(arguments, **options) @@ -62,7 +56,8 @@ def libdoc(app: Application, robot_options_and_args: Tuple[str, ...]) -> None: robot_arguments = None try: - _, robot_arguments = LibDoc().parse_arguments(robot_options_and_args) + with app.save_syspath(): + _, robot_arguments = LibDoc().parse_arguments(robot_options_and_args) except (DataError, Information): pass @@ -73,32 +68,34 @@ def libdoc(app: Application, robot_options_and_args: Tuple[str, ...]) -> None: no_vcs=app.config.no_vcs, verbose_callback=app.verbose, ) - try: - profile = ( - load_robot_config_from_path(*config_files, verbose_callback=app.verbose) - .combine_profiles(*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error) - .evaluated_with_env(verbose_callback=app.verbose, error_callback=app.error) - ) - except (TypeError, ValueError) as e: - raise click.ClickException(str(e)) from e + with app.chdir(root_folder): + try: + profile = ( + load_robot_config_from_path(*config_files, verbose_callback=app.verbose) + .combine_profiles(*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error) + .evaluated_with_env(verbose_callback=app.verbose, error_callback=app.error) + ) - libdoc_options = profile.libdoc - if libdoc_options is None: - libdoc_options = LibDocProfile() + except (TypeError, ValueError) as e: + raise click.ClickException(str(e)) from e - libdoc_options.add_options(profile) + libdoc_options = profile.libdoc + if libdoc_options is None: + libdoc_options = LibDocProfile() - options = libdoc_options.build_command_line() + libdoc_options.add_options(profile) - app.verbose( - lambda: "Executing libdoc robot with the following options:\n " - + " ".join(f'"{o}"' for o in (options + list(robot_options_and_args))) - ) + options = libdoc_options.build_command_line() - app.exit( - cast( - int, - LibDocEx(app.config.dry, root_folder).execute_cli((*options, *robot_options_and_args), exit=False), + app.verbose( + lambda: "Executing libdoc robot with the following options:\n " + + " ".join(f'"{o}"' for o in (options + list(robot_options_and_args))) + ) + + app.exit( + cast( + int, + LibDocEx(app.config.dry).execute_cli((*options, *robot_options_and_args), exit=False), + ) ) - ) diff --git a/packages/runner/src/robotcode/runner/cli/rebot.py b/packages/runner/src/robotcode/runner/cli/rebot.py index dda20f68..fd79c9d5 100644 --- a/packages/runner/src/robotcode/runner/cli/rebot.py +++ b/packages/runner/src/robotcode/runner/cli/rebot.py @@ -1,6 +1,5 @@ import os -from pathlib import Path -from typing import Any, Optional, Tuple, cast +from typing import Any, Tuple, cast import click from robot.errors import DataError, Information @@ -17,10 +16,9 @@ class RebotEx(Rebot): - def __init__(self, dry: bool, root_folder: Optional[Path]) -> None: + def __init__(self, dry: bool) -> None: super().__init__() self.dry = dry - self.root_folder = root_folder def parse_arguments(self, cli_args: Any) -> Any: options, arguments = super().parse_arguments(cli_args) @@ -36,9 +34,6 @@ def parse_arguments(self, cli_args: Any) -> Any: return options, arguments def main(self, datasources: Any, **options: Any) -> Any: - if self.root_folder is not None: - os.chdir(self.root_folder) - return super().main(datasources, **options) @@ -63,7 +58,8 @@ def rebot(app: Application, robot_options_and_args: Tuple[str, ...]) -> None: robot_arguments = None try: - _, robot_arguments = Rebot().parse_arguments(robot_options_and_args) + with app.save_syspath(): + _, robot_arguments = Rebot().parse_arguments(robot_options_and_args) except (DataError, Information): pass @@ -75,46 +71,47 @@ def rebot(app: Application, robot_options_and_args: Tuple[str, ...]) -> None: verbose_callback=app.verbose, ) - try: - profile = ( - load_robot_config_from_path(*config_files, verbose_callback=app.verbose) - .combine_profiles(*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error) - .evaluated_with_env(verbose_callback=app.verbose, error_callback=app.error) - ) + with app.chdir(root_folder): + try: + profile = ( + load_robot_config_from_path(*config_files, verbose_callback=app.verbose) + .combine_profiles(*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error) + .evaluated_with_env(verbose_callback=app.verbose, error_callback=app.error) + ) - except (TypeError, ValueError) as e: - raise click.ClickException(str(e)) from e + except (TypeError, ValueError) as e: + raise click.ClickException(str(e)) from e - rebot_options = profile.rebot - if rebot_options is None: - rebot_options = RebotProfile() + rebot_options = profile.rebot + if rebot_options is None: + rebot_options = RebotProfile() - rebot_options.add_options(profile) + rebot_options.add_options(profile) - try: - options = rebot_options.build_command_line() - except (TypeError, ValueError) as e: - raise click.ClickException(str(e)) from e + try: + options = rebot_options.build_command_line() + except (TypeError, ValueError) as e: + raise click.ClickException(str(e)) from e - app.verbose( - lambda: "Executing rebot with the following options:\n " - + " ".join(f'"{o}"' for o in (options + list(robot_options_and_args))) - ) + app.verbose( + lambda: "Executing rebot with the following options:\n " + + " ".join(f'"{o}"' for o in (options + list(robot_options_and_args))) + ) - console_links_args = [] - if get_robot_version() >= (7, 1) and os.getenv("ROBOTCODE_DISABLE_ANSI_LINKS", "").lower() in [ - "on", - "1", - "yes", - "true", - ]: - console_links_args = ["--consolelinks", "off"] - - app.exit( - cast( - int, - RebotEx(app.config.dry, root_folder).execute_cli( - (*options, *console_links_args, *robot_options_and_args), exit=False - ), + console_links_args = [] + if get_robot_version() >= (7, 1) and os.getenv("ROBOTCODE_DISABLE_ANSI_LINKS", "").lower() in [ + "on", + "1", + "yes", + "true", + ]: + console_links_args = ["--consolelinks", "off"] + + app.exit( + cast( + int, + RebotEx(app.config.dry).execute_cli( + (*options, *console_links_args, *robot_options_and_args), exit=False + ), + ) ) - ) diff --git a/packages/runner/src/robotcode/runner/cli/robot.py b/packages/runner/src/robotcode/runner/cli/robot.py index affad3cd..29309a2e 100644 --- a/packages/runner/src/robotcode/runner/cli/robot.py +++ b/packages/runner/src/robotcode/runner/cli/robot.py @@ -1,5 +1,4 @@ import os -import sys import weakref from pathlib import Path from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast @@ -156,6 +155,7 @@ def __init__( paths: List[str], dry: bool, root_folder: Optional[Path], + orig_folder: Optional[Path], by_longname: Tuple[str, ...] = (), exclude_by_longname: Tuple[str, ...] = (), ) -> None: @@ -164,15 +164,11 @@ def __init__( self.paths = paths self.dry = dry self.root_folder = root_folder - self._orig_cwd = Path.cwd() + self._orig_cwd = Path.cwd() if orig_folder is None else orig_folder self.by_longname = by_longname self.exclude_by_longname = exclude_by_longname def parse_arguments(self, cli_args: Any) -> Any: - if self.root_folder is not None and Path.cwd() != self.root_folder: - self.app.verbose(f"Changing working directory from {self._orig_cwd} to {self.root_folder}") - os.chdir(self.root_folder) - try: options, arguments = super().parse_arguments(cli_args) if self.root_folder is not None: @@ -253,13 +249,12 @@ def handle_robot_options( _patch() robot_arguments: Optional[List[Union[str, Path]]] = None - old_sys_path = sys.path.copy() + try: - _, robot_arguments = RobotFramework().parse_arguments(robot_options_and_args) + with app.save_syspath(): + _, robot_arguments = RobotFramework().parse_arguments(robot_options_and_args) except (DataError, Information): pass - finally: - sys.path = old_sys_path config_files, root_folder, _ = get_config_files( robot_arguments, @@ -322,29 +317,31 @@ def robot( root_folder, profile, cmd_options = handle_robot_options(app, robot_options_and_args) - console_links_args = [] - if get_robot_version() >= (7, 1) and os.getenv("ROBOTCODE_DISABLE_ANSI_LINKS", "").lower() in [ - "on", - "1", - "yes", - "true", - ]: - console_links_args = ["--consolelinks", "off"] - - app.exit( - cast( - int, - RobotFrameworkEx( - app, - ( - [*(app.config.default_paths if app.config.default_paths else ())] - if profile.paths is None - else profile.paths if isinstance(profile.paths, list) else [profile.paths] - ), - app.config.dry, - root_folder, - by_longname, - exclude_by_longname, - ).execute_cli((*cmd_options, *console_links_args, *robot_options_and_args), exit=False), + with app.chdir(root_folder) as orig_folder: + console_links_args = [] + if get_robot_version() >= (7, 1) and os.getenv("ROBOTCODE_DISABLE_ANSI_LINKS", "").lower() in [ + "on", + "1", + "yes", + "true", + ]: + console_links_args = ["--consolelinks", "off"] + + app.exit( + cast( + int, + RobotFrameworkEx( + app, + ( + [*(app.config.default_paths if app.config.default_paths else ())] + if profile.paths is None + else profile.paths if isinstance(profile.paths, list) else [profile.paths] + ), + app.config.dry, + root_folder, + orig_folder, + by_longname, + exclude_by_longname, + ).execute_cli((*cmd_options, *console_links_args, *robot_options_and_args), exit=False), + ) ) - ) diff --git a/packages/runner/src/robotcode/runner/cli/testdoc.py b/packages/runner/src/robotcode/runner/cli/testdoc.py index 5a1aad0d..1f4c8e7f 100644 --- a/packages/runner/src/robotcode/runner/cli/testdoc.py +++ b/packages/runner/src/robotcode/runner/cli/testdoc.py @@ -1,6 +1,4 @@ -import os -from pathlib import Path -from typing import Any, Optional, Tuple, cast +from typing import Any, Tuple, cast import click from robot.errors import DataError, Information @@ -16,10 +14,9 @@ class TestDocEx(TestDoc): - def __init__(self, dry: bool, root_folder: Optional[Path]) -> None: + def __init__(self, dry: bool) -> None: super().__init__() self.dry = dry - self.root_folder = root_folder def parse_arguments(self, cli_args: Any) -> Any: options, arguments = super().parse_arguments(cli_args) @@ -35,9 +32,6 @@ def parse_arguments(self, cli_args: Any) -> Any: return options, arguments def main(self, arguments: Any, **options: Any) -> Any: - if self.root_folder is not None: - os.chdir(self.root_folder) - return super().main(arguments, **options) @@ -62,7 +56,8 @@ def testdoc(app: Application, robot_options_and_args: Tuple[str, ...]) -> None: robot_arguments = None try: - _, robot_arguments = TestDoc().parse_arguments(robot_options_and_args) + with app.save_syspath(): + _, robot_arguments = TestDoc().parse_arguments(robot_options_and_args) except (DataError, Information): pass @@ -74,32 +69,33 @@ def testdoc(app: Application, robot_options_and_args: Tuple[str, ...]) -> None: verbose_callback=app.verbose, ) - try: - profile = ( - load_robot_config_from_path(*config_files, verbose_callback=app.verbose) - .combine_profiles(*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error) - .evaluated_with_env(verbose_callback=app.verbose, error_callback=app.error) - ) + with app.chdir(root_folder): + try: + profile = ( + load_robot_config_from_path(*config_files, verbose_callback=app.verbose) + .combine_profiles(*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error) + .evaluated_with_env(verbose_callback=app.verbose, error_callback=app.error) + ) - except (TypeError, ValueError) as e: - raise click.ClickException(str(e)) from e + except (TypeError, ValueError) as e: + raise click.ClickException(str(e)) from e - testdoc_options = profile.testdoc - if testdoc_options is None: - testdoc_options = TestDocProfile() + testdoc_options = profile.testdoc + if testdoc_options is None: + testdoc_options = TestDocProfile() - testdoc_options.add_options(profile) + testdoc_options.add_options(profile) - options = testdoc_options.build_command_line() + options = testdoc_options.build_command_line() - app.verbose( - lambda: "Executing testdoc with the following options:\n " - + " ".join(f'"{o}"' for o in (options + list(robot_options_and_args))) - ) + app.verbose( + lambda: "Executing testdoc with the following options:\n " + + " ".join(f'"{o}"' for o in (options + list(robot_options_and_args))) + ) - app.exit( - cast( - int, - TestDocEx(app.config.dry, root_folder).execute_cli((*options, *robot_options_and_args), exit=False), + app.exit( + cast( + int, + TestDocEx(app.config.dry).execute_cli((*options, *robot_options_and_args), exit=False), + ) ) - ) From 39fad12e6cc8d1246dc45c8e843fa1c3b046a491 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Wed, 4 Dec 2024 15:30:35 +0100 Subject: [PATCH 07/13] feat(vscode): added some better file icons --- icons/dark/robot-book.png | Bin 0 -> 8025 bytes icons/dark/robot-book.svg | 93 +++++++++++++++++++++++++++++++++++++ icons/dark/robot-repl.png | Bin 0 -> 11107 bytes icons/dark/robot-repl.svg | 60 ++++++++++++++++++++++++ icons/dark/robot.png | Bin 0 -> 6753 bytes icons/dark/robot.svg | 42 +++++++++++++++++ icons/light/robot-book.png | Bin 0 -> 8025 bytes icons/light/robot-book.svg | 93 +++++++++++++++++++++++++++++++++++++ icons/light/robot-repl.png | Bin 0 -> 11107 bytes icons/light/robot-repl.svg | 60 ++++++++++++++++++++++++ icons/light/robot.png | Bin 0 -> 6753 bytes icons/light/robot.svg | 42 +++++++++++++++++ icons/robot-dark.png | Bin 4550 -> 0 bytes icons/robot-light.png | Bin 5583 -> 0 bytes icons/svg/robot_dark.svg | 39 ---------------- icons/svg/robot_light.svg | 39 ---------------- package.json | 24 ++++++++-- 17 files changed, 409 insertions(+), 83 deletions(-) create mode 100644 icons/dark/robot-book.png create mode 100644 icons/dark/robot-book.svg create mode 100644 icons/dark/robot-repl.png create mode 100644 icons/dark/robot-repl.svg create mode 100644 icons/dark/robot.png create mode 100644 icons/dark/robot.svg create mode 100644 icons/light/robot-book.png create mode 100644 icons/light/robot-book.svg create mode 100644 icons/light/robot-repl.png create mode 100644 icons/light/robot-repl.svg create mode 100644 icons/light/robot.png create mode 100644 icons/light/robot.svg delete mode 100644 icons/robot-dark.png delete mode 100644 icons/robot-light.png delete mode 100644 icons/svg/robot_dark.svg delete mode 100644 icons/svg/robot_light.svg diff --git a/icons/dark/robot-book.png b/icons/dark/robot-book.png new file mode 100644 index 0000000000000000000000000000000000000000..75697b9d0d8d7735cd99951e114278e9995a61ea GIT binary patch literal 8025 zcmbW6c|4Ts|Nrl?SJqQW7&JL0yOTYX8kIKdWEo3lk}!iXWQjQuYS1BDl&y$c#y+wu z$B?yRjNOEY$(G38_j1nnzu)8ceSE%OkH9q?2d&T!c z5F}uH5p51Z2+iFO9}j3@*VgBQe|x+x+W0_F{ow8g@%;Hj253C&Yh>+f;d#r~-^tq< z^7r>wcJ*-g!8>_5D|>poq|NJzLy**zG1}1b?z6d(fV=k2Rho;NHmA-Ri+z&E$+O69 zB7Y+cRrFfz_U^rZNpJ6~RN8?191mwwJEv5g`eY_b+w!$+P=kVNkPWX)$hAgZ4re*} zVEI-jU2n-VXWsc<{PWYT{viD^>4y`pu1{Y3Hw4vf?$}%Xa_ie1b}e0?)~$-8F^1^L zCygWsm0e!aAJuwFQ4{rDkP;JB+k`ucS}6V>ny!VhAscl)z2P4}dQ2*-y9@{7+P~17 zRENiPFVqP;a5daJckbLi`NTF6DAtt0iM|;M6+s`qYKuE}ml?-Dvz0sG;fH)FRouVx zc9v1#pP}VB>I!d&KnomWREt2mT22rg>>%luus6J~jl|uCLTD)o;A1u)* zVegVv{UatWF0L#nC}=;^FxaB9S+wPj14ac=OkpcpHdwAa;@&5!IP>*uir4ez<15w# zT=We02evNX$MQ6KON+_e%uGNRN!YO$TVkAVDgW@|C`mXw)aydL?1J)vy(ZOy<6+gh ziCLEN_8sOg#8+rCd>#_w;(>*18H2nueVTS`4Q9ohsT1XQLzeIU{_5)Lc|W9V`)qc9 z?&5%qmPz9XL+b~Ev3v!XMe7W+pnW{2{BuD2Da9hPq!5u@aq`*g*bNXSQ0tse8~ET zlihkgox7Xlk9^q|fF++I~5c+@=JZs(Hk>`;GDNt9Bw_dd%Iyq{vA zjB)(_y${}@g1K* zqqqu1p!SX|TyTj^mh0fk6jTRHX$ z{vFSs@d6T}5ZjZKf@StG6cAock}Zx!KMM}jZcc$MSPS=q-QmHW(b4)*F^fu})m3VL zysYc)!+D+wvQjnN`+C2e5?go_6SXrAW?SntH&_u=Eoe>zXQBbAtD_T;rgrNz(-3~x ze15WF8ydEiPaOTGd$9tXlG$@LQNxxhRws79w**64372wy)(GMxC^32U>Xg=l^b}>L zAput+!pM+>@XS_;vWW=YQv9Sgd<>bx0s9^p^2kLUKf+%*yUXV4c$}jDQ4FAL& z8QJC|cNf}L%qkQX7Ahcu#m`VCtVxm0*Y(pNMS-TpNNU($_Y|zC!+Tl#fLpP$luuNE zY8j;5z;}2AW64xG`BXyA_0S|0$DNwo++2TnRtT8naYfC|kV9N=Yj)dDF%4T|y1Keb z!1?xt)?(R;EBBjkF`JCz6=!E>1A9rr-UTmSy!az@XX`Qarh}9e*oZ5e{&*?J+c(Sf zZYxO`7C<7A2O(*ZIO(dc@l&E{NE67q9M}Bl^c%sm6~FU0y{FM=LhvkxTDBJ5oK*h` zJ=w3yA3CAS$HeMowa*GrD}v=fongQ=Mu4@$l%ZF2xhvcvsmte&U7PMj~4#LFsamVt^s~8qeZo zrcLlWTw0A19O#{8y7mBEyy_%oFx1=Yt4BU%=d#32A$rg_v`;+Bj-iH`(nx-O9&QAJ zo=9UIm@TRV8>f#Jbvd#=1J+z5PZizYnIIeamm zi=J`{@eCR9*@W0-TY_umydx?73f4mO_e?2fEEax^JwZOXyuKwq6vo5LJNDtjhsAxE zZPm51d=f9`n~!44WWgOPsU0dG#8)ujS5`;ZPU| z6CNhe#f4VCe$FmW&^i{=Dw+n;O5lbmRD8K2`>yI~#U2XZ+gVvh{g@K`g(hNbCNlCJG+}R77{Pz93=?tZCcdD%yIqIpPs0pNNcG6Qqm%&&@c6e zs;a6qP!fWr`jls`B5?(may~ij4((eN^_!U zZU>Bh7Qic)cS`R!^8}AfVLy=AeVv?(oEZJKK7KeL=uxY{9m$5#slR0S>Z9{7Lu`k- zLs%W-c+Vl*VX+=<5N^526U5HUj@woY0ZvZNzAl?*^|=W`4-k~OB(UT!V;;n)#lV3& z(fAOtO zaRny#GNQv`wz?lZ$<#~&zD9{dd*t2VWF#}G{YzS|=do0HX=$mZalaqCrXT341#<`U zXf>WQR&DI~PzNE_@nnaEZlZ;o4p#)dC1&B#Rp8sZ-`jg z+qG`SFhQ`I_S~kUC%-WYtQOMy0%6;q)1?ejNls2fL#WjieX~cmHEmNR8h$>BE^BXvoh{XAWFgS@6l@JMtY(9@3 z{r@$I+wo??dC*?#~$%8lXv-4D)WW$G_8ga|a5s1oFoRyzH zL)-QCNMf-Y1GcxdwH@8VvK9$YA#)NVWlR5To=R4O+{0wVfb*}$=SmdWRe39r1$sga zz*1zv)skn9lgm9LtS`@7Fx=6T4iFY9=j<11%!gj<-+l1Ssbt-WZ1);2fWA3?A*k~z(xNRG zSj2&Bx$3dLXka|YA(z8=9P~RBIgpC^{UCG*p?&&M_WQYeW}cp&94v8shZ4M@A@bfz z=}6}uic*a{>ibhw{)Q-d{q0lyO+i2c3xbZn)X5Gvm%}2)D6JQO3+wjx3sdEvGP)h37q{ZjdIsl;gqs4KR>EBWE2<_ z)D9WM;gn0mo0F7G;MtmNxeXJhA(Uw;|v?jVzFU;UeoWtP| z^+(x5cGLYyGd*X|GIe&YphK?bTMD*KFDLg~J7Pjz@%ER5C`uAn4j7I3Ajg}-oz{?$ zJF+E3IL@S^q5@g98@>C*f8#O~jaBH=NS`;`l;SAx-?+=<=f;a>ON*$~g zdFyfW^(OS>6tE9Yrp_(YqwIF0Nf(Ux&pcRpZ|FK9N7-!q$dnkc18;kYPY7ZM-hKus*miG&8d;Y>^fdO{Vatg z4vIx&RkSB;Y;HOlXlt)UynSovo-zNxNgIW7wF~@F3`>Dn!~C4r8?B}U?zDomN1B6E zb>>SLGMGA@ISpo!<5;zGdr~5*^fhq*4C8nRidJhl6n6wu_xC&3-?b2H(>jD-rd4(Z zuWM>Hm&!RhElaF}-G#Z>Z--vG?ETsA)q`2PB-N<(qq!jXKsH+dB_1T7ng#~@_t^%<< zuY9%0QeNw|eT`pt`7KJTe%Z)%3rLkieh6# z;&^*(+r`RM$U>c7JHO$t1lb-|UD4}#x?z+mlrwO+8Mow2PmxAMA--Mj97r$#x0o@e z&F$DDDeK+Z$5F>~6A_Js`izWR?a;_^?GR64uAk6dPmSq#eXy6S9UFa&q2e)ura8lg zSc&ZJ#-+i-qOD>*9IUgD3kENR5uy~*^W5A{?-vPJSJb+?T=M#DvAm~96F(XG$6%7p!Gx%n0ps(8KVI6r4t2SE_sz^xmvo)eeD{6gI$L-@ zU1O=y27MZTU|;GSmXhj1++8NnFpP7+Ax&-7l!R<=T<;j)GmFA~K`oo-`!;_4`W0lc z3peruVw$f9*+P=~Or!G`E(mchezNh{DP3J%JvW`|1a_7Jb)?Ps!GTvoLw`|yp8s;W zckkYxYPWKth7l}Qd0)<8Gp^w3bQcLB^0a4J1+((3>K3%PWaFV#l$Dir>cP4yy}Yur z(vh20kYe=ST(bn&jmRCz?v36sT*=)8xND}DTVzI+E@?0{H=(@)k&jLbe;%$%H#yX@ zbQqfF{cCDQAprpvAqQpyCBwc|Z4b=QNSJGkTgE3^22#$rTJ`sxtw79k_V%O$2dkw_ zXH;8Vy*v|S{#1C3Z^WPNSuBvYtTZr@k5x8)S_=Kw?cv)AHOIY)e$A^k7q>)q?V70}O>>G7>FwGc)F(IBop#F= zEJ&qx6`(44jLUFQhI}4#PaxO8$bo;yphtZNb+d&E>7rk9LOWZH4sr1OGXN6~LtS1! z8d>^AFD2I4KTXP&^yvSC9{A5x!~eFI(3P&F;|P9AYXwm4SyNL}$LVx>8};1!MT~#v z7w;fSYZ_E5-FSx;d*)Vgf2k8k;{&i%?Lefa*+=H@e*sA$yd=o+YEw6$WJr71Retcq zmUP}~%rWCqZT_ZZ8@Kszr@P0=cu0(CbGyZwP(d_Dk6QhM!ota_{KuPAqanK~-FC8DW4cfWm$BuO@E_wmNmI@Mz;s!Y65EOb$Bf9zeW>R!)tb-27GR8=M1%gvL zZl~-oK~ApjI;#?^mD&-pA0UZ^aqaqI^Zej4Q#rjET~nk8zGDcpq9+oN!B#Ezu_g?Z zoWV34;CgEWGDJ1f&@(e;mR_G6Dky&zizufo`rHRugtH06`fKL&%{aI^_DtE|`2R?r z{%dI1y_PFB%)@d+=9nYoP& zVb}FLB(J7|?DQ=9`l~wSfazFZ=KGVCu&cqT6mh(5Bd-qAzXYM(PtOK=fdFx8_8n6h z*4NRgdQ(=`Lq8$K8}^v{^(L-tMb;B}`0#oPOf4%naAs};kfOWXaq?FSeH;!o=8^S^-;2Ey3kRF~HtOo?oH6?L z=#ZQ4JdE1NC$c)Uf&#W#yH8g|ZOE2jpHqqn-iRBe_EiHfO&D$wS_=E}2b4Qz0w_-YvG&MB= zm@KxqvUO-HGUXEotEOifvgsKZ(BWYnfGYc+ozwU{BWoOsEx|olp$use2YrtyKCeyy zIHVzv5)}+0sJ4sGMF4g{GHeWmfP_{@Lmou|sI-p8dl-Kfqu;Xn?6p(Lwg5)oxhMCk zI|!w(cWQk7{XM0mrB9ooL!7`ZOLpJ{Qm@9Hx}T*)>kX8U4L&}QbG zHye=ZYnaEpiwbEzc`z++_WgsiZ#P1%=_wXQlcykYLU$VqpadnNr>Dx>?>Q#`F9MP? zmUqz|^p~eW|G**|??0N-84?HNL0)udl>{IFh8FqSx&&8VQgTO)yh-dvxgSGMmaFo6 zmg?tO$}5>Oq&aTW^cC8z2`XpNU9l7W8^ow2W%~_FVXhXaIM5cdQ9FW?Zk=9c_DkK2 z*0Do}KsVC=1tAFV_F_HmLD#ITnEQciy$k&uNH@wK;Ad^G2aj$%WYSZb5O(`A=RHwX zC#?ymri1Yv$B9BS^YbA$gM+u8!-0F&yi#m)Au5L94}5LK9AHae7sVATo*#o}b7 zS4)J+ylMILeLCFf_VybI=(S@*J&8d0wg|A+BR-+un0%OfXEC7|xdS_vF#*7UJuk;k z@<2q|Em>o4Q;n{wf@2|;dM6##=vQ_}7|xoB4BGm8RT8$Rr-Z4loVroi8{Ax(eex)D zJ^513{ayC;=bwLWtF2sYNq*B6Zv?p5evuh1y6-M*1DjXW{>591<8Bq;Y0bDaB*Ijk z{%l^CZ@pQptSHJ(=tkDRpsh}l?3r{aC-e?7eCq=sszPKy#6I0g=)jkB{x>ReU>eE| zffrN|7Z>;7Sabtaun|zf^BANiy|#rU+?I; z-?XLYxG+S~xDm@03?#_qb%0!VuVy4fw4{G{NT4wYs=aV?c2UAnY~XDMhBzL{`~N_Y zS_M!%Y6B$`=ZBAr4lg_^v{P2jJS$r^vJW%Ii(Q~LqcsNFmwGN7)bGc)2&ufegu zeFKDE2h?Bw7#~Pams)U889g{u{>u+ZmOC0Up-UEU5KV(e*#+^%)9P0rRpZ9$pmY4LfRRzFEDbn*M9u*34Fp!Ce za(fB~Zi+9_`hluw5V%2MOQJPqxuN7LK_^OOGtGDA)2rP~R506C7L}vQpW*ksNz{`f z0HG&w5Y~QL23Awan@zTlEPl_%r5UIOW`O}J&=?iICa=Fqf@!tNnvj^Zbc0wUC)G!o z5w&?p(Ym;e#5Yu{LIa}Z4uoW3&9l`+bb#W-zat5Qc1?({X;BJN0E2rQqq{n$m;I}{ z%mheg1V}i-X;0&!-3ycVgAE$!q$syI-JswUF+2~1riKY)DDWz<2sMbbj4J~5I#=-s zCqv9>z~ap`KvB``!1IT?@*0^ttNlBu*okYHx&voG-4HEWn+cDY9k|y+5xX1w zCpa-cg@O9eKC?&jpeFVM0PSDi$iEW_a#u3Jjbr; zCF_Dh9rhoV2NpC4dd7XDo~?&IxmX+ZgV)e&>HC-Vj629&(cQu+C|da`B)2c{7IQV4 zLEawwMTi!M8$03ZdZ2+CYHEVY*k>xj0gnc0KvZiS9LPoHguV%}4nnCT$6n~36l9q| zQl^Yei0~{W + + + + + + + + + diff --git a/icons/dark/robot-repl.png b/icons/dark/robot-repl.png new file mode 100644 index 0000000000000000000000000000000000000000..017729c1619eab52b55a263d04fde3bf8a725b5a GIT binary patch literal 11107 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

Z8& zn9m5^hN?oG!mga$XlM#AMH$T+17C64;xp+YbCZ1RZ$iX5lrw-A^56kb%~4tbmr@n8 z8}g=5NF`^`hM@^~61^~v=n!EAWU%Mn0;8aws)ojMAXuFfF5W4NEVsP#-+zBTn>gE9 z)&S?_n%=dGs@?8O-Qr)R&(=?GYy_gBqN12FKZ@5sB=&x}*`Pn>csBD_C5lb4df2}A z=mKy0nZ2k^e>8fH2fFevf7dp%v*tV4!h$hk@&p4T9`i%313cQWnXl745Q?Y}>OiJE zbYF6~8146=8+DWT8+zrlYK&%v5B;pge14grc@AYZZb#p_*8xomZ?d4US~`}S}66$8=>Mfn{83cax+LK z|M~OwmjH~Hl;y%de^>jO4+uYj;2migo@cfCVywOBnd@Z?cHJP3CDgc(nJ~lZY8JlL z%;u0euv|$b64T^@R533ew^Jg*;$eJ+PhbCiC~l!&1H%yaFADz~zGJ09y&wbaW}1{3 zh0cbIi%m~WEh4^3DXXcy4XU-9$-vINC(u#-rN*cl&fIuhWnu>2$w=5l}qIKu@e**&CD|<3K|e;v6j78f2C1OTSF$1)G$Z z7i#RyV=Kb>9Zo5?SX%Oo3M5RcQ_d$}e746+~`7gsxedIH8KOYh9_J-a9Oa zViF{!bi;-|Jye!$D64*Q?L4^kra_=-@~f8QOg?a3>UIFP)?`q}<;&p**-Xm#ja0v@ zKdDS*PHhl%IN9`sC)tr(DQFemPom;Au2h(B-@ZKn3bzzy1X|;t(9^@dyvu_RhZs!C ze-(0`R+>;5u^*@Us{!AZqZkPe;27j{M)wkB}kPkBe z{gp%Uv%~dX_9Y{OtCz!7$HvG1y?pV)LzwVEpS4LkQ;dD>0|EG!p-?2`1(OrdVaHrb zR~Cz(Nbetz3V`Ik5X_;wGj(qg4Gj(XKmYvC*(Sw+2dzgBr+(2KNiT@x`~T@W=Kt+| c(7i78V0DIv??b!61zG5d!8K%+o@?Cy0)bH^NB{r; literal 0 HcmV?d00001 diff --git a/icons/dark/robot-repl.svg b/icons/dark/robot-repl.svg new file mode 100644 index 00000000..303ce13e --- /dev/null +++ b/icons/dark/robot-repl.svg @@ -0,0 +1,60 @@ + + + + + + + + diff --git a/icons/dark/robot.png b/icons/dark/robot.png new file mode 100644 index 0000000000000000000000000000000000000000..2ab33d164c22bd8aac89d047671760eb2a2ca694 GIT binary patch literal 6753 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 sV+}hvs+g{>_k literal 0 HcmV?d00001 diff --git a/icons/dark/robot.svg b/icons/dark/robot.svg new file mode 100644 index 00000000..0848aa8c --- /dev/null +++ b/icons/dark/robot.svg @@ -0,0 +1,42 @@ + + + + + + diff --git a/icons/light/robot-book.png b/icons/light/robot-book.png new file mode 100644 index 0000000000000000000000000000000000000000..75697b9d0d8d7735cd99951e114278e9995a61ea GIT binary patch literal 8025 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 + + + + + + + + + diff --git a/icons/light/robot-repl.png b/icons/light/robot-repl.png new file mode 100644 index 0000000000000000000000000000000000000000..017729c1619eab52b55a263d04fde3bf8a725b5a GIT binary patch literal 11107 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

Z8& zn9m5^hN?oG!mga$XlM#AMH$T+17C64;xp+YbCZ1RZ$iX5lrw-A^56kb%~4tbmr@n8 z8}g=5NF`^`hM@^~61^~v=n!EAWU%Mn0;8aws)ojMAXuFfF5W4NEVsP#-+zBTn>gE9 z)&S?_n%=dGs@?8O-Qr)R&(=?GYy_gBqN12FKZ@5sB=&x}*`Pn>csBD_C5lb4df2}A z=mKy0nZ2k^e>8fH2fFevf7dp%v*tV4!h$hk@&p4T9`i%313cQWnXl745Q?Y}>OiJE zbYF6~8146=8+DWT8+zrlYK&%v5B;pge14grc@AYZZb#p_*8xomZ?d4US~`}S}66$8=>Mfn{83cax+LK z|M~OwmjH~Hl;y%de^>jO4+uYj;2migo@cfCVywOBnd@Z?cHJP3CDgc(nJ~lZY8JlL z%;u0euv|$b64T^@R533ew^Jg*;$eJ+PhbCiC~l!&1H%yaFADz~zGJ09y&wbaW}1{3 zh0cbIi%m~WEh4^3DXXcy4XU-9$-vINC(u#-rN*cl&fIuhWnu>2$w=5l}qIKu@e**&CD|<3K|e;v6j78f2C1OTSF$1)G$Z z7i#RyV=Kb>9Zo5?SX%Oo3M5RcQ_d$}e746+~`7gsxedIH8KOYh9_J-a9Oa zViF{!bi;-|Jye!$D64*Q?L4^kra_=-@~f8QOg?a3>UIFP)?`q}<;&p**-Xm#ja0v@ zKdDS*PHhl%IN9`sC)tr(DQFemPom;Au2h(B-@ZKn3bzzy1X|;t(9^@dyvu_RhZs!C ze-(0`R+>;5u^*@Us{!AZqZkPe;27j{M)wkB}kPkBe z{gp%Uv%~dX_9Y{OtCz!7$HvG1y?pV)LzwVEpS4LkQ;dD>0|EG!p-?2`1(OrdVaHrb zR~Cz(Nbetz3V`Ik5X_;wGj(qg4Gj(XKmYvC*(Sw+2dzgBr+(2KNiT@x`~T@W=Kt+| c(7i78V0DIv??b!61zG5d!8K%+o@?Cy0)bH^NB{r; literal 0 HcmV?d00001 diff --git a/icons/light/robot-repl.svg b/icons/light/robot-repl.svg new file mode 100644 index 00000000..303ce13e --- /dev/null +++ b/icons/light/robot-repl.svg @@ -0,0 +1,60 @@ + + + + + + + + diff --git a/icons/light/robot.png b/icons/light/robot.png new file mode 100644 index 0000000000000000000000000000000000000000..2ab33d164c22bd8aac89d047671760eb2a2ca694 GIT binary patch literal 6753 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 sV+}hvs+g{>_k literal 0 HcmV?d00001 diff --git a/icons/light/robot.svg b/icons/light/robot.svg new file mode 100644 index 00000000..0848aa8c --- /dev/null +++ b/icons/light/robot.svg @@ -0,0 +1,42 @@ + + + + + + diff --git a/icons/robot-dark.png b/icons/robot-dark.png deleted file mode 100644 index 57a6488f5720638d5e077325434ae56f30eac411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4550 zcmb7Ic{CJW{~qQ$WDKKhV;dp+*eiQ7L-u`X$TD`yZe%dZk{MfRRAb2~*%etMsisUr z4MRl8zJ$u2DAGH9|NfoddEa}^UC;CR+~=Nq&;302X4>1D@qk6a004l;!ra7>Rd4>y zM>treD8qq^RdGd{yTt$ix6l5~Y~RO@GFgKnSW`6CDIyRX=MxMF;4GF&#{Fk(heL6UA z@2GHi-wejHrTF~%CfPTm-h0+=_vz9^%>GYjheN5|gDa>Vt)+=iOHBRbYFq9?m&?_#Vp7B28HvjPW>=)#0K2$YyG+gG!?SASs-EU7A#kbKR?Qh? zCqYB}jVw$EFobNA$xP(vS`7^VHIMRl6qW}V(LjN0aZV+%6(z6)b$pso33$>nuSsm~ zRF03d5ujd{VN@k<$;GG(ohLkEz8gD;jHo1e9>Cfau*!L&594!x;>l2y_MH0<cJhn*&E2A2qOj`sz<_IK)n>v2YhkYJ+$5|>CC95yxnp_cG2#!|8 z0&Q;tJHa5dk`_OsOrW{(t^8r(UK!w?M2BFetz6(jJL(a@YV`p$x|3z|hEkm-9+V-7 ziBcOs-Yx74Lg(=Z+?)qDvLoJRtM+VOL$e88eE^OY|BHPYoLYRyr%XL&D`0H9d!tUZ zND#xNkVWxap=AEg_*ms)kiHDv3)ujq@`+1C168gObYM7s`}HdiHdfraM;7si-Cub>&%@J(kcKvVW;`guSDs%+PLIMsgl<=)O_iiSs=3|?29U!KiZZzFWT*AY4{~bYJ)JO5jVJi?MyS@ z9a4pc$1h)?o{*_*lIYqR2y<4R;uHIm=q%d>xrA)9ufw4{=2{0-%n747BfCuk>=#n| zxQOrEZ-Y1DzDJFvgfdHzh-13x=o8W4M)L&$Us8`EO`7DCVJcn4mu;dt>hx8su19AE zf{=jOzKPZ(Y@%=6$LoK7M!k%9j2XRF(c^QFH#92rWK%D&vGhVU8Tsv!i-XBr_FORMug0rqBY7S0R(WIC}A=&WZ{ZjvvO$J zN@dL4#hpk^kgKm7(FfiN!YKfI=^NexxFYF$mvt`deOJ$y%R-ZZORuH?`4X7{stq}w z26j;4^bk#6@MdtG4+QiAbpt+w&%0_nR@I1gn1P?(Ph7C_Etx$6K2Ro@CBGFEk1`tqg6rC>xacSVA9mYJ6!Fo?-}qSAY8~I_ z#Z+De+8rg$G>u1T|JUrZ5g5E2;rdM*Bks`50MU1mO#N9_-Vj-`>!=b+1%kF8=_+dGyoXngXYTNo_u#) zcP2aw&$_E*zC0*ow@UT~$m@vz6i>KV)JLpZ#GVr@uq?SVv%XnYh7~qdJu*pS1LJRS zg#v_T548e&G`cqn+--vf<>)}=20Q|*ETg2RCW!&wgG_?$ryeEvzjgnhksDm1b(ILEqPSUI0>dT0?o{u0jDRLbtvh9YGDzTW zU)Dmag;~#qylY^Sle5RHK3to6gEoX7A!?)@c)@3U9IAM;;b~NIZNTPQd zJR~1owp660iKs#+Q-S#di#YFH4qIQaoqb6X$_wOeseg%I#Er268SSaz+w21Y5t4qX zWqo`?DCl`oRr0L0yr1j(^h!XKZ<$$V@d%2IJjT`XYHz zGV1xWx0=uB^E{?xV19c@^~HYQpQ5XwM<&c_Lv(+W`gP&!F44ud`V1nE`dQ^%2VahX z#r7XukCsMjbJrHZuQ_ngNPhjoQh;O;60%5~n8hl4OA@%1ekqlw#f|pmQ#Y;Z#cC() zo|kkrPAs?NzgKje!;ZJ7Fmcl&-)eh%K37~%g7h3kvt3QmYLH3A~UtrP2~-eaNgG{{3m={AKSOI93&Tp zx3YU8ZkXQQJIV8h5EtV2yE=CtA?dq!z4;6V?_zc*ICiwF^x-SdP6k$QueH0Q@WI0& z0J)L3yY_J632j~CN?$C_#Y`kZf5huVxA)*{r;;xLee@+ zsS(W^-r9U>LScZ(jb3~Bl-NY<88YV1)e}|IEy~owh+b&$aN5}p4xr?&d+(< zaNCSLd?07ah^5j+&*5%~3lGu_DxH&3`qcVpBJb%?jS1H`q~}yq=4mBZJYN?r}nc;J;giZcDOiG~hk3Sa$Wl$AOqG z>j9#Z!a0YG==NfJ5c1-(vrL_8MbGupyXO4qxCX(6w~dfs$YhrIH6IOAcT^im2)v1@ z>*Y++aqQ3Q-kKZ;D^Eun6a-vZ7Ai*)Vpak}mroC#m71Dd+FALq139dINZF^=bDFtVW_UZE=AUDBt8?mb=_o}8?YwFN zc0ELoVD@xZ54@MjgO*ZfZre_Q)~5H(PQOPl7}pCLqqG^73%X^?y;e~)Fk6F^o#jErACUAw488~NG%P|jiQ@?Y8a zu3125e5JtV8&+@1c#nIN*a<~f`H8-;B}M2;IDN4qMX+D}igRYbr(z5~XB?!rA6S>G zFuPkPkkF6%lINQqQ-?=QTw^W-2gI?@^D=gIqcr=^X--(Dq-W-+j5+(WMF#nnB`#>w z$W_P0f4lbeIFhy?cr)L5`F&lZOJ$ZJ=5!&FH1p#$$Cn$@R>J za|C)81pzm;I}q6jE!SWI{xvof4%nc8ul>ymy;yOK`KMckdSkC_nVcmXj*mN~{7L!l zc{y9ZsV~?&$yZ+7tOTIO1LxQlMdD8#*1P}7I9DIg^iu3;#W|MbGqP$txL%cYX=TZy zvT4%kc~*rMZN{jF(AF>k{riwJd28iaQ~U~}!@+P{*i#~BmMB%7rr!L_m-Z*dp9HK} z6US9!i7ZZBiaTrs7?Q>F8lP#h6qzqA6>-LtACsX-yMH_z>HvcIa%(8`SeKs5tR(j!RKLWJnA@ZdU^1?qx4*n=jevFQV;LXkwK$E#nV+h@E!wNvs+E$3!alZR9zrlJnT5?eC8bz{1qlq#lV${SU`@HLd^v diff --git a/icons/robot-light.png b/icons/robot-light.png deleted file mode 100644 index f81f2e656692f1410e6616e1040928dbab577a18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5583 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 j&40&FUcVkWeo2a8=%Eek>~|)TvA_czLvX2 - - - - - diff --git a/icons/svg/robot_light.svg b/icons/svg/robot_light.svg deleted file mode 100644 index cc3ecc08..00000000 --- a/icons/svg/robot_light.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - diff --git a/package.json b/package.json index 07f686dc..75f94479 100644 --- a/package.json +++ b/package.json @@ -385,8 +385,8 @@ "robotframework" ], "icon": { - "light": "./icons/robot-light.png", - "dark": "./icons/robot-dark.png" + "light": "./icons/light/robot.png", + "dark": "./icons/dark/robot.png" }, "extensions": [ ".robot", @@ -401,16 +401,30 @@ "robotframework repl" ], "icon": { - "light": "./icons/robot-light.png", - "dark": "./icons/robot-dark.png" + "light": "./icons/light/robot-repl.png", + "dark": "./icons/dark/robot-repl.png" }, "extensions": [ - ".robotrepl" + ".robotrepl", + ".robotsript" ], "configuration": "./language-configuration.json" }, { "id": "robotframework-injection" + }, + { + "id": "robotframework-notebook", + "aliases": [ + "Robot Framework Notebook" + ], + "icon": { + "light": "./icons/light/robot-book.png", + "dark": "./icons/dark/robot-book.png" + }, + "extensions": [ + ".robotbook" + ] } ], "grammars": [ From 170287db04ec811e39b7ec5e7bd853ae9d98ec7c Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 5 Dec 2024 16:18:31 +0100 Subject: [PATCH 08/13] fix(vscode): corrected highlightning of bold/italic in documentation tags --- .../codeblock_robotframework.tmLanguage.json | 30 ++---- syntaxes/robotframework-repl.tmLanguage.json | 69 ++++++++------ syntaxes/robotframework.tmLanguage.json | 94 ++++++++++++------- .../robotframework.tmLanguage.template.json | 94 ++++++++++++------- 4 files changed, 162 insertions(+), 125 deletions(-) diff --git a/syntaxes/codeblock_robotframework.tmLanguage.json b/syntaxes/codeblock_robotframework.tmLanguage.json index 3c35cbb7..6cc805e2 100644 --- a/syntaxes/codeblock_robotframework.tmLanguage.json +++ b/syntaxes/codeblock_robotframework.tmLanguage.json @@ -1,10 +1,8 @@ { - "fileTypes": [], + "fileTypes": [ ], "injectionSelector": "L:text.html.markdown", "patterns": [ - { - "include": "#robotframework-code-block" - } + { "include": "#robotframework-code-block" } ], "repository": { "robotframework-code-block": { @@ -12,31 +10,17 @@ "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { - "3": { - "name": "punctuation.definition.markdown" - }, - "4": { - "name": "fenced_code.block.language.markdown" - }, - "5": { - "name": "fenced_code.block.language.attributes.markdown" - } - }, - "endCaptures": { - "3": { - "name": "punctuation.definition.markdown" - } + "3": { "name": "punctuation.definition.markdown" }, + "4": { "name": "fenced_code.block.language.markdown" }, + "5": { "name": "fenced_code.block.language.attributes.markdown" } }, + "endCaptures": { "3": { "name": "punctuation.definition.markdown" } }, "patterns": [ { "begin": "(^|\\G)(\\s*)(.*)", "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", "contentName": "meta.embedded.block.robotframework", - "patterns": [ - { - "include": "source.robotframework" - } - ] + "patterns": [ { "include": "source.robotframework" } ] } ] } diff --git a/syntaxes/robotframework-repl.tmLanguage.json b/syntaxes/robotframework-repl.tmLanguage.json index 5520e265..2e442c55 100644 --- a/syntaxes/robotframework-repl.tmLanguage.json +++ b/syntaxes/robotframework-repl.tmLanguage.json @@ -132,34 +132,42 @@ ] }, "documentation_bold": { - "contentName": "markup.bold.documentation.robotframework", - "begin": "(\\*)(\\**)", - "end": "(\\*)*(\\*)|$", - "beginCaptures": { "1": { "name": "markup.robotframework" } }, - "endCaptures": { "2": { "name": "markup.robotframework" } }, - "patterns": [ - { "include": "#documentation_italic" }, - { "include": "#escape" }, - { "include": "#comment" }, - { "include": "#comment_line" }, - { "include": "#variables" }, - { "include": "#line_continuation" } - ] + "match": "(?:(?<=\\s|^))(\\*)(?:(?=\\S))(.*?)(?:(?<=\\S))(\\*)(?:(?=\\s|_))", + "captures": { + "1": { "name": "punctuation.definition.italic.markdown" }, + "2": { + "name": "markup.bold.documentation.robotframework", + "patterns": [ + { "include": "#documentation_italic" }, + { "include": "#documentation_bold" }, + { "include": "#escape" }, + { "include": "#comment" }, + { "include": "#comment_line" }, + { "include": "#variables" }, + { "include": "#line_continuation" } + ] + }, + "3": { "name": "punctuation.definition.italic.markdown" } + } }, "documentation_italic": { - "contentName": "markup.italic.documentation.robotframework", - "begin": "(_)(_*)", - "end": "(_*)(_)|$", - "beginCaptures": { "1": { "name": "markup.robotframework" } }, - "endCaptures": { "2": { "name": "markup.robotframework" } }, - "patterns": [ - { "include": "#documentation_bold" }, - { "include": "#escape" }, - { "include": "#comment" }, - { "include": "#comment_line" }, - { "include": "#variables" }, - { "include": "#line_continuation" } - ] + "match": "(?:(?<=\\s|^))(_)(?:(?=\\S))(.*?)(?:(?<=\\S))(_)(?:(?=\\s|\\*))", + "captures": { + "1": { "name": "punctuation.definition.italic.markdown" }, + "2": { + "name": "markup.italic.documentation.robotframework", + "patterns": [ + { "include": "#documentation_italic" }, + { "include": "#documentation_bold" }, + { "include": "#escape" }, + { "include": "#comment" }, + { "include": "#comment_line" }, + { "include": "#variables" }, + { "include": "#line_continuation" } + ] + }, + "3": { "name": "punctuation.definition.italic.markdown" } + } }, "testcase_name": { "contentName": "string.unquoted.argument.robotframework", @@ -389,11 +397,12 @@ "contentName": "string.unquoted.argument.robotframework", "begin": "^(?:\\s*)([$@&]{(\\s?[^\\s|\\}](\\s?[^\\s|\\}]+?)*)*\\s?}(\\s?\\[(\\s?[^\\s|\\]](\\s?[^\\s|\\]]+?)*)*\\s?\\])*)( ?=?)(?: {2,}| ?\\t ?)(\\S(\\s?\\S)*)", "beginCaptures": { - "1": { - "patterns": [ { "include": "#variables" } ] - }, + "1": { "patterns": [ { "include": "#variables" } ] }, "7": { "name": "keyword.operator.robotframework" }, - "8": { "name": "entity.name.function.keyword-call.robotframework", "patterns": [ { "include": "#variables" } ] } + "8": { + "name": "entity.name.function.keyword-call.robotframework", + "patterns": [ { "include": "#variables" } ] + } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", "patterns": [ diff --git a/syntaxes/robotframework.tmLanguage.json b/syntaxes/robotframework.tmLanguage.json index 59efdcc7..4f26df81 100644 --- a/syntaxes/robotframework.tmLanguage.json +++ b/syntaxes/robotframework.tmLanguage.json @@ -7,7 +7,10 @@ "begin": "^([$@&]\\{)(.*?)(\\})( ?=?)", "beginCaptures": { "1": { "name": "punctuation.definition.variable.begin.robotframework" }, - "2": { "name": "variable.name.readwrite.robotframework", "patterns": [{"include": "#variables"}] }, + "2": { + "name": "variable.name.readwrite.robotframework", + "patterns": [ { "include": "#variables" } ] + }, "3": { "name": "punctuation.definition.variable.end.robotframework" }, "4": { "name": "keyword.operator.robotframework" } }, @@ -129,39 +132,52 @@ ] }, "documentation_bold": { - "contentName": "markup.bold.documentation.robotframework", - "begin": "(\\*)(\\**)", - "end": "(\\*)*(\\*)|$", - "beginCaptures": { "1": { "name": "markup.robotframework" } }, - "endCaptures": { "2": { "name": "markup.robotframework" } }, - "patterns": [ - { "include": "#documentation_italic" }, - { "include": "#escape" }, - { "include": "#comment" }, - { "include": "#comment_line" }, - { "include": "#variables" }, - { "include": "#line_continuation" } - ] + "match": "(?:(?<=\\s|^))(\\*)(?:(?=\\S))(.*?)(?:(?<=\\S))(\\*)(?:(?=\\s|_))", + "captures": { + "1": { "name": "punctuation.definition.italic.markdown" }, + "2": { + "name": "markup.bold.documentation.robotframework", + "patterns": [ + { "include": "#documentation_italic" }, + { "include": "#documentation_bold" }, + { "include": "#escape" }, + { "include": "#comment" }, + { "include": "#comment_line" }, + { "include": "#variables" }, + { "include": "#line_continuation" } + ] + }, + "3": { "name": "punctuation.definition.italic.markdown" } + } }, "documentation_italic": { - "contentName": "markup.italic.documentation.robotframework", - "begin": "(_)(_*)", - "end": "(_*)(_)|$", - "beginCaptures": { "1": { "name": "markup.robotframework" } }, - "endCaptures": { "2": { "name": "markup.robotframework" } }, - "patterns": [ - { "include": "#documentation_bold" }, - { "include": "#escape" }, - { "include": "#comment" }, - { "include": "#comment_line" }, - { "include": "#variables" }, - { "include": "#line_continuation" } - ] + "match": "(?:(?<=\\s|^))(_)(?:(?=\\S))(.*?)(?:(?<=\\S))(_)(?:(?=\\s|\\*))", + "captures": { + "1": { "name": "punctuation.definition.italic.markdown" }, + "2": { + "name": "markup.italic.documentation.robotframework", + "patterns": [ + { "include": "#documentation_italic" }, + { "include": "#documentation_bold" }, + { "include": "#escape" }, + { "include": "#comment" }, + { "include": "#comment_line" }, + { "include": "#variables" }, + { "include": "#line_continuation" } + ] + }, + "3": { "name": "punctuation.definition.italic.markdown" } + } }, "testcase_name": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", - "beginCaptures": { "1": { "name": "entity.name.function.testcase.name.robotframework", "patterns": [{"include": "#variables"}] } }, + "beginCaptures": { + "1": { + "name": "entity.name.function.testcase.name.robotframework", + "patterns": [ { "include": "#variables" } ] + } + }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", "patterns": [ { "include": "#escape" }, @@ -174,7 +190,12 @@ "keyword_name": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", - "beginCaptures": { "1": { "name": "entity.name.function.keyword.name.robotframework", "patterns": [{"include": "#only_dollar_var"}] } }, + "beginCaptures": { + "1": { + "name": "entity.name.function.keyword.name.robotframework", + "patterns": [ { "include": "#only_dollar_var" } ] + } + }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", "patterns": [ { "include": "#escape" }, @@ -313,7 +334,12 @@ "contentName": "string.unquoted.argument.robotframework", "begin": "^(?!(?: {2,}| ?\\t ?)+(?:(?=[$\\[@&%]|\\.)))(?: {2,}| ?\\t ?)+(.*?)(?= {2,}| ?\\t ?| ?$)", "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", - "beginCaptures": { "1": { "name": "entity.name.function.keyword-call.robotframework", "patterns": [{"include": "#variables"}]} }, + "beginCaptures": { + "1": { + "name": "entity.name.function.keyword-call.robotframework", + "patterns": [ { "include": "#variables" } ] + } + }, "patterns": [ { "include": "#escape" }, { "include": "#comment" }, @@ -381,9 +407,7 @@ "contentName": "string.unquoted.argument.robotframework", "begin": "(?<=\\s)(?=\\s*(?:(?=[$@&])))((?:\\s)*(?:[$&@]{(?:.*?)}(?:\\[.*?\\])?(?: ?=?\\s*))*)(.*?)(?: {2,}| ?\\t ?|$)", "beginCaptures": { - "1": { - "patterns": [ { "include": "#variable_assignment_from_kw" } ] - }, + "1": { "patterns": [ { "include": "#variable_assignment_from_kw" } ] }, "2": { "name": "entity.name.function.keyword-call.robotframework" } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -398,9 +422,7 @@ "begin": "(?<=^\\s)(?:\\s*)(?=[$@&])", "end": "(?:( ?=)|(?: {2,}| ?\\t+ ?| ?$)(?![#$@& \\n\\r]|\\.\\.\\.)|^(?=\\.\\.\\.)( {2,}| ?\\t+ ?| ?$)(?![#$@&]))", "endCaptures": { "1": { "name": "keyword.operator.robotframework" } }, - "patterns": [ - { "include": "#variables" } - ] + "patterns": [ { "include": "#variables" } ] }, "line_continuation": { "match": "^(\\s*\\.\\.\\.)(?! ?\\S)", diff --git a/syntaxes/robotframework.tmLanguage.template.json b/syntaxes/robotframework.tmLanguage.template.json index 3274417a..2d86ead6 100644 --- a/syntaxes/robotframework.tmLanguage.template.json +++ b/syntaxes/robotframework.tmLanguage.template.json @@ -7,7 +7,10 @@ "begin": "^([$@&]\\{)(.*?)(\\})( ?=?)", "beginCaptures": { "1": { "name": "punctuation.definition.variable.begin.robotframework" }, - "2": { "name": "variable.name.readwrite.robotframework", "patterns": [{"include": "#variables"}] }, + "2": { + "name": "variable.name.readwrite.robotframework", + "patterns": [ { "include": "#variables" } ] + }, "3": { "name": "punctuation.definition.variable.end.robotframework" }, "4": { "name": "keyword.operator.robotframework" } }, @@ -129,39 +132,52 @@ ] }, "documentation_bold": { - "contentName": "markup.bold.documentation.robotframework", - "begin": "(\\*)(\\**)", - "end": "(\\*)*(\\*)|$", - "beginCaptures": { "1": { "name": "markup.robotframework" } }, - "endCaptures": { "2": { "name": "markup.robotframework" } }, - "patterns": [ - { "include": "#documentation_italic" }, - { "include": "#escape" }, - { "include": "#comment" }, - { "include": "#comment_line" }, - { "include": "#variables" }, - { "include": "#line_continuation" } - ] + "match": "(?:(?<=\\s|^))(\\*)(?:(?=\\S))(.*?)(?:(?<=\\S))(\\*)(?:(?=\\s|_))", + "captures": { + "1": { "name": "punctuation.definition.italic.markdown" }, + "2": { + "name": "markup.bold.documentation.robotframework", + "patterns": [ + { "include": "#documentation_italic" }, + { "include": "#documentation_bold" }, + { "include": "#escape" }, + { "include": "#comment" }, + { "include": "#comment_line" }, + { "include": "#variables" }, + { "include": "#line_continuation" } + ] + }, + "3": { "name": "punctuation.definition.italic.markdown" } + } }, "documentation_italic": { - "contentName": "markup.italic.documentation.robotframework", - "begin": "(_)(_*)", - "end": "(_*)(_)|$", - "beginCaptures": { "1": { "name": "markup.robotframework" } }, - "endCaptures": { "2": { "name": "markup.robotframework" } }, - "patterns": [ - { "include": "#documentation_bold" }, - { "include": "#escape" }, - { "include": "#comment" }, - { "include": "#comment_line" }, - { "include": "#variables" }, - { "include": "#line_continuation" } - ] + "match": "(?:(?<=\\s|^))(_)(?:(?=\\S))(.*?)(?:(?<=\\S))(_)(?:(?=\\s|\\*))", + "captures": { + "1": { "name": "punctuation.definition.italic.markdown" }, + "2": { + "name": "markup.italic.documentation.robotframework", + "patterns": [ + { "include": "#documentation_italic" }, + { "include": "#documentation_bold" }, + { "include": "#escape" }, + { "include": "#comment" }, + { "include": "#comment_line" }, + { "include": "#variables" }, + { "include": "#line_continuation" } + ] + }, + "3": { "name": "punctuation.definition.italic.markdown" } + } }, "testcase_name": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", - "beginCaptures": { "1": { "name": "entity.name.function.testcase.name.robotframework", "patterns": [{"include": "#variables"}] } }, + "beginCaptures": { + "1": { + "name": "entity.name.function.testcase.name.robotframework", + "patterns": [ { "include": "#variables" } ] + } + }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", "patterns": [ { "include": "#escape" }, @@ -174,7 +190,12 @@ "keyword_name": { "contentName": "string.unquoted.argument.robotframework", "begin": "^( ?\\S+( ?\\S*)*?)(?= {2}| ?\\t| ?$)", - "beginCaptures": { "1": { "name": "entity.name.function.keyword.name.robotframework", "patterns": [{"include": "#only_dollar_var"}] } }, + "beginCaptures": { + "1": { + "name": "entity.name.function.keyword.name.robotframework", + "patterns": [ { "include": "#only_dollar_var" } ] + } + }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", "patterns": [ { "include": "#escape" }, @@ -313,7 +334,12 @@ "contentName": "string.unquoted.argument.robotframework", "begin": "^(?!(?: {2,}| ?\\t ?)+(?:(?=[$\\[@&%]|\\.)))(?: {2,}| ?\\t ?)+(.*?)(?= {2,}| ?\\t ?| ?$)", "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", - "beginCaptures": { "1": { "name": "entity.name.function.keyword-call.robotframework", "patterns": [{"include": "#variables"}]} }, + "beginCaptures": { + "1": { + "name": "entity.name.function.keyword-call.robotframework", + "patterns": [ { "include": "#variables" } ] + } + }, "patterns": [ { "include": "#escape" }, { "include": "#comment" }, @@ -381,9 +407,7 @@ "contentName": "string.unquoted.argument.robotframework", "begin": "(?<=\\s)(?=\\s*(?:(?=[$@&])))((?:\\s)*(?:[$&@]{(?:.*?)}(?:\\[.*?\\])?(?: ?=?\\s*))*)(.*?)(?: {2,}| ?\\t ?|$)", "beginCaptures": { - "1": { - "patterns": [ { "include": "#variable_assignment_from_kw" } ] - }, + "1": { "patterns": [ { "include": "#variable_assignment_from_kw" } ] }, "2": { "name": "entity.name.function.keyword-call.robotframework" } }, "end": "^(?!(\\s*(\\.\\.\\.((( {2}| ?\\t)\\s*\\S.*)|(\\s*))?$))|(\\s*#.*$)|(\\s*$))", @@ -398,9 +422,7 @@ "begin": "(?<=^\\s)(?:\\s*)(?=[$@&])", "end": "(?:( ?=)|(?: {2,}| ?\\t+ ?| ?$)(?![#$@& \\n\\r]|\\.\\.\\.)|^(?=\\.\\.\\.)( {2,}| ?\\t+ ?| ?$)(?![#$@&]))", "endCaptures": { "1": { "name": "keyword.operator.robotframework" } }, - "patterns": [ - { "include": "#variables" } - ] + "patterns": [ { "include": "#variables" } ] }, "line_continuation": { "match": "^(\\s*\\.\\.\\.)(?! ?\\S)", From 9185ccd84dbb9f2f5cd2aba4212598abd93ef0f1 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 5 Dec 2024 16:41:08 +0100 Subject: [PATCH 09/13] feat(vscode): preview of Robot Framework Notebook support for VSCode --- .vscode/launch.json | 39 +- .vscodeignore | 2 +- esbuild.mjs | 83 ++ eslint.config.mjs | 4 +- hatch.toml | 2 +- package-lock.json | 885 ++++++------------ package.json | 247 ++++- .../core/src/robotcode/core/concurrent.py | 4 +- .../src/robotcode/core/utils/dataclasses.py | 1 + .../debugger/src/robotcode/debugger/run.py | 11 +- .../jsonrpc2/src/robotcode/jsonrpc2/server.py | 19 +- packages/repl/README.md | 3 +- packages/repl/pyproject.toml | 1 - .../{interpreter.py => base_interpreter.py} | 214 ++--- packages/repl/src/robotcode/repl/cli.py | 141 +++ .../repl/src/robotcode/repl/cli/__init__.py | 3 - packages/repl/src/robotcode/repl/cli/repl.py | 232 ----- .../src/robotcode/repl/console_interpreter.py | 142 +++ .../repl/src/robotcode/repl/repl_listener.py | 25 - packages/repl/src/robotcode/repl/run.py | 133 +++ packages/repl_server/LICENSE.txt | 73 ++ packages/repl_server/README.md | 21 + packages/repl_server/pyproject.toml | 60 ++ .../src/robotcode/repl_server/__init__.py | 0 .../src/robotcode/repl_server/__version__.py | 1 + .../src/robotcode/repl_server/cli.py | 236 +++++ .../src/robotcode/repl_server/hooks.py | 12 + .../src/robotcode/repl_server/html_writer.py | 324 +++++++ .../src/robotcode/repl_server/interpreter.py | 366 ++++++++ .../src/robotcode/repl_server/protocol.py | 32 + .../src/robotcode/repl_server/py.typed | 1 + .../src/robotcode/repl_server/server.py | 24 + pyproject.toml | 4 +- tsconfig.json | 44 - .../vscode.proposed.notebookReplDocument.d.ts | 35 - vscode-client/{ => extension}/config.ts | 0 vscode-client/{ => extension}/debugmanager.ts | 0 .../{extension.ts => extension/index.ts} | 0 .../keywordsTreeViewProvider.ts | 0 .../{ => extension}/languageToolsManager.ts | 0 .../{ => extension}/languageclientsmanger.ts | 0 vscode-client/{ => extension}/net_utils.ts | 0 vscode-client/extension/notebook.ts | 437 +++++++++ vscode-client/{ => extension}/pythonmanger.ts | 0 .../{ => extension}/testcontrollermanager.ts | 0 vscode-client/extension/tsconfig.json | 23 + vscode-client/{ => extension}/utils.ts | 5 + vscode-client/notebook.ts | 126 --- vscode-client/rendererHtml/css/common.csstemp | 476 ++++++++++ .../rendererHtml/css/doc_formatting.csstemp | 77 ++ vscode-client/rendererHtml/css/log.csstemp | 302 ++++++ vscode-client/rendererHtml/css/print.csstemp | 58 ++ vscode-client/rendererHtml/index.tsx | 75 ++ .../rendererHtml/js/jquery.min.jstemp | 2 + vscode-client/rendererHtml/js/log.jstemp | 279 ++++++ vscode-client/rendererHtml/js/util.jstemp | 224 +++++ vscode-client/rendererHtml/tsconfig.json | 20 + vscode-client/rendererHtml/types.d.ts | 9 + vscode-client/rendererLog/common.css | 156 +++ vscode-client/rendererLog/docFormatting.css | 67 ++ vscode-client/rendererLog/index.tsx | 40 + vscode-client/rendererLog/log.css | 277 ++++++ vscode-client/rendererLog/renderer.tsx | 557 +++++++++++ vscode-client/rendererLog/tsconfig.json | 27 + vscode-client/rendererLog/types.d.ts | 9 + vscode-client/test/runTest.ts | 23 - vscode-client/tsconfig.base.json | 18 + 67 files changed, 5412 insertions(+), 1299 deletions(-) create mode 100644 esbuild.mjs rename packages/repl/src/robotcode/repl/{interpreter.py => base_interpreter.py} (54%) create mode 100644 packages/repl/src/robotcode/repl/cli.py delete mode 100644 packages/repl/src/robotcode/repl/cli/__init__.py delete mode 100644 packages/repl/src/robotcode/repl/cli/repl.py create mode 100644 packages/repl/src/robotcode/repl/console_interpreter.py delete mode 100644 packages/repl/src/robotcode/repl/repl_listener.py create mode 100644 packages/repl/src/robotcode/repl/run.py create mode 100644 packages/repl_server/LICENSE.txt create mode 100644 packages/repl_server/README.md create mode 100644 packages/repl_server/pyproject.toml create mode 100644 packages/repl_server/src/robotcode/repl_server/__init__.py create mode 100644 packages/repl_server/src/robotcode/repl_server/__version__.py create mode 100644 packages/repl_server/src/robotcode/repl_server/cli.py create mode 100644 packages/repl_server/src/robotcode/repl_server/hooks.py create mode 100644 packages/repl_server/src/robotcode/repl_server/html_writer.py create mode 100644 packages/repl_server/src/robotcode/repl_server/interpreter.py create mode 100644 packages/repl_server/src/robotcode/repl_server/protocol.py create mode 100644 packages/repl_server/src/robotcode/repl_server/py.typed create mode 100644 packages/repl_server/src/robotcode/repl_server/server.py delete mode 100644 tsconfig.json delete mode 100644 types/vscode.proposed.notebookReplDocument.d.ts rename vscode-client/{ => extension}/config.ts (100%) rename vscode-client/{ => extension}/debugmanager.ts (100%) rename vscode-client/{extension.ts => extension/index.ts} (100%) rename vscode-client/{ => extension}/keywordsTreeViewProvider.ts (100%) rename vscode-client/{ => extension}/languageToolsManager.ts (100%) rename vscode-client/{ => extension}/languageclientsmanger.ts (100%) rename vscode-client/{ => extension}/net_utils.ts (100%) create mode 100644 vscode-client/extension/notebook.ts rename vscode-client/{ => extension}/pythonmanger.ts (100%) rename vscode-client/{ => extension}/testcontrollermanager.ts (100%) create mode 100644 vscode-client/extension/tsconfig.json rename vscode-client/{ => extension}/utils.ts (95%) delete mode 100644 vscode-client/notebook.ts create mode 100644 vscode-client/rendererHtml/css/common.csstemp create mode 100644 vscode-client/rendererHtml/css/doc_formatting.csstemp create mode 100644 vscode-client/rendererHtml/css/log.csstemp create mode 100644 vscode-client/rendererHtml/css/print.csstemp create mode 100644 vscode-client/rendererHtml/index.tsx create mode 100644 vscode-client/rendererHtml/js/jquery.min.jstemp create mode 100644 vscode-client/rendererHtml/js/log.jstemp create mode 100644 vscode-client/rendererHtml/js/util.jstemp create mode 100644 vscode-client/rendererHtml/tsconfig.json create mode 100644 vscode-client/rendererHtml/types.d.ts create mode 100644 vscode-client/rendererLog/common.css create mode 100644 vscode-client/rendererLog/docFormatting.css create mode 100644 vscode-client/rendererLog/index.tsx create mode 100644 vscode-client/rendererLog/log.css create mode 100644 vscode-client/rendererLog/renderer.tsx create mode 100644 vscode-client/rendererLog/tsconfig.json create mode 100644 vscode-client/rendererLog/types.d.ts delete mode 100644 vscode-client/test/runTest.ts create mode 100644 vscode-client/tsconfig.base.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 110d363f..da3dc584 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,31 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Attach to Node Process", + "port": 9229, + "request": "attach", + "skipFiles": [ + "/**" + ], + "type": "node", + "autoAttachChildProcesses": true + }, + + + { + "name": "esbuild.mjs", + "program": "${workspaceFolder}/esbuild.mjs", + "request": "launch", + "skipFiles": [ + "/**" + ], + "type": "node", + "console": "integratedTerminal", + "runtimeArgs": [ + "--experimental-modules" + ] + }, { "name": "Python: Debug in terminal", "type": "debugpy", @@ -53,9 +78,10 @@ // "suites", // // "discover", "tests", "--tags" // "." - // "discover", - // "files", - // ".." + "discover", + "--no-diagnostics", + "all", + ".." // "config", // "show", // "discover", @@ -66,9 +92,10 @@ // "E:\\source\\uvtestprj\\tests\\first.robotrepl" // "analyze", // "code", - "--help" + // "--help" // "tests" - //"repl", + // "repl-server", + // "package.json" // "-v", // "asd:asd" @@ -185,6 +212,8 @@ "args": [ "--extensionDevelopmentPath=${workspaceFolder}", ], + "debugWebviews": true, + "debugWebWorkerHost": true, "outFiles": [ "${workspaceFolder}/out/**/*.js" ], diff --git a/.vscodeignore b/.vscodeignore index 6450a14c..8d70303d 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -39,7 +39,7 @@ pyproject.toml **/playground/ # svg files -**/*.svg +#**/*.svg # coverage .coverage diff --git a/esbuild.mjs b/esbuild.mjs new file mode 100644 index 00000000..18e27e9b --- /dev/null +++ b/esbuild.mjs @@ -0,0 +1,83 @@ +import * as esbuild from "esbuild"; +import * as process from "process"; +import { typecheckPlugin } from "@jgoz/esbuild-plugin-typecheck"; +/** + * @type {import('esbuild').LogLevel} + */ +const LOG_LEVEL = "error"; + +/** + * @type {boolean} + */ +const production = process.argv.includes("--production"); + +/** + * @type {import('esbuild').BuildOptions[]} + */ +const projects = [ + { + entryPoints: ["./vscode-client/extension"], + format: "cjs", + platform: "node", + outfile: "out/extension.js", + external: ["vscode"], + }, + { + entryPoints: ["./vscode-client/rendererHtml"], + format: "esm", + platform: "browser", + outfile: "out/rendererHtml.js", + external: ["vscode"], + loader: { + ".jstemp": "text", + ".csstemp": "text", + }, + }, + { + entryPoints: ["./vscode-client/rendererLog"], + format: "esm", + platform: "browser", + outfile: "out/rendererLog.js", + external: ["vscode"], + loader: { + ".ttf": "file", + ".css": "text", + }, + }, +]; + +/** + * + * @param {import('esbuild').BuildOptions} project + */ +async function buildProject(project) { + const ctx = await esbuild.context({ + bundle: true, + minify: production, + sourcemap: !production, + sourcesContent: false, + logLevel: LOG_LEVEL, + + ...project, + + plugins: [ + typecheckPlugin({ configFile: project.entryPoints[0] + "/tsconfig.json" }), + /* add to the end of plugins array */ + //esbuildProblemMatcherPlugin, + ], + }); + + await ctx.rebuild(); + await ctx.dispose(); +} + +async function main() { + for (const project of projects) { + await buildProject(project); + } +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/eslint.config.mjs b/eslint.config.mjs index 52a1c3c7..4ae71029 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -17,9 +17,11 @@ export default [ "**/.pytest_cache/", "**/site/", "**/docs/", + "**/packages/", + "**/js", ], }, - { files: ["**/*.{js,mjs,cjs,ts}"] }, + { files: ["**/*.{ts,tsx}"] }, { languageOptions: { globals: globals.browser } }, pluginJs.configs.recommended, ...tseslint.configs.recommended, diff --git a/hatch.toml b/hatch.toml index 5a681204..d17021bb 100644 --- a/hatch.toml +++ b/hatch.toml @@ -13,7 +13,7 @@ only-include = ["src", "CHANGELOG.md"] [envs.default] -installer = "uv" +#installer = "uv" dependencies = [ "pytest", "pytest-html", diff --git a/package-lock.json b/package-lock.json index 9b291c4c..a7d7cb78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,20 +17,21 @@ "docs" ], "dependencies": { - "@vscode/python-extension": "^1.0.5", + "@vscode/codicons": "^0.0.36", "ansi-colors": "^4.1.3", "fs-extra": "^11.2.0", - "robotcode": "file:", "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@eslint/compat": "^1.2.3", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.15.0", + "@jgoz/esbuild-plugin-typecheck": "^4.0.2", "@types/fs-extra": "^11.0.4", "@types/node": "^22.9.1", - "@types/vscode": "^1.86.0", - "@vscode/test-electron": "^2.4.1", + "@types/vscode": "^1.90.0", + "@types/vscode-notebook-renderer": "^1.72.3", + "@vscode/python-extension": "^1.0.5", "@vscode/vsce": "^3.2.1", "esbuild": "^0.24.0", "eslint": "^9.15.0", @@ -38,13 +39,14 @@ "eslint-plugin-prettier": "^5.2.1", "globals": "^15.12.0", "ovsx": "^0.10.1", - "prettier": "^3.3.3", + "preact": "^10.25.0", + "prettier": "^3.4.1", "ts-loader": "^9.5.1", - "typescript": "^5.6.3", - "typescript-eslint": "^8.15.0" + "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0" }, "engines": { - "vscode": "^1.86.0" + "vscode": "^1.90.0" } }, "docs": { @@ -353,9 +355,9 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.0.tgz", - "integrity": "sha512-QSoGUp4Eq/gohEFNJaUOwTN7BCc2nHTjjbm75JT0aD7W65PWM1H/tItz0GsABn22uaKyGxiMhWQLt2r+FGU89Q==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.1.tgz", + "integrity": "sha512-/wS73UEDrxroUEVywEm7J0p2c+IIiVxyfigCGfsKvCxxCET4V/Hef2aURqltrXMRjNmdmt5IuOgIpl8f6xdO5A==", "dev": true, "license": "MIT", "dependencies": { @@ -1207,9 +1209,9 @@ } }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.12.tgz", - "integrity": "sha512-lRNORrIdeLStShxAjN6FgXE1iMkaAgiAHZdP0P0GZecX91FVYW58uZnRSlXLlSx5cxMoELulkAAixybPA2g52g==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.13.tgz", + "integrity": "sha512-rRQjMoIt/kPfaD+fnBC9YZQpso3hkn8xPeadl+YWhscJ5SVUCdB9oTeR9VIpt+/5Yi8vEkh2UOWFPq4lz3ee2A==", "dev": true, "license": "CC0-1.0", "dependencies": { @@ -1241,6 +1243,23 @@ "node": ">=12" } }, + "node_modules/@jgoz/esbuild-plugin-typecheck": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@jgoz/esbuild-plugin-typecheck/-/esbuild-plugin-typecheck-4.0.2.tgz", + "integrity": "sha512-EI0b2xLA+12YauKdXZ8wbdn3cKaKPBsh20S4Y0DyPENhhUALKYX6InuDMBD+9EKDHhcTqpCBkQVutFyx6l4RJA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@jgoz/esbuild-plugin-livereload": ">=2.1.2", + "esbuild": "0.17.x || 0.18.x || 0.19.x || 0.20.x || 0.21.x || 0.22.x || 0.23.x || 0.24.x", + "typescript": ">= 3.5" + }, + "peerDependenciesMeta": { + "@jgoz/esbuild-plugin-livereload": { + "optional": true + } + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -1373,9 +1392,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.3.tgz", - "integrity": "sha512-EzxVSkIvCFxUd4Mgm4xR9YXrcp976qVaHnqom/Tgm+vU79k4vV4eYTjmRvGfeoW8m9LVcsAy/lGjcgVegKEhLQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", "cpu": [ "arm" ], @@ -1387,9 +1406,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.3.tgz", - "integrity": "sha512-LJc5pDf1wjlt9o/Giaw9Ofl+k/vLUaYsE2zeQGH85giX2F+wn/Cg8b3c5CDP3qmVmeO5NzwVUzQQxwZvC2eQKw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", "cpu": [ "arm64" ], @@ -1401,9 +1420,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.3.tgz", - "integrity": "sha512-OuRysZ1Mt7wpWJ+aYKblVbJWtVn3Cy52h8nLuNSzTqSesYw1EuN6wKp5NW/4eSre3mp12gqFRXOKTcN3AI3LqA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", "cpu": [ "arm64" ], @@ -1415,9 +1434,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.3.tgz", - "integrity": "sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", "cpu": [ "x64" ], @@ -1429,9 +1448,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.3.tgz", - "integrity": "sha512-58E0tIcwZ+12nK1WiLzHOD8I0d0kdrY/+o7yFVPRHuVGY3twBwzwDdTIBGRxLmyjciMYl1B/U515GJy+yn46qw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", "cpu": [ "arm64" ], @@ -1443,9 +1462,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.3.tgz", - "integrity": "sha512-78fohrpcVwTLxg1ZzBMlwEimoAJmY6B+5TsyAZ3Vok7YabRBUvjYTsRXPTjGEvv/mfgVBepbW28OlMEz4w8wGA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", "cpu": [ "x64" ], @@ -1457,9 +1476,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.3.tgz", - "integrity": "sha512-h2Ay79YFXyQi+QZKo3ISZDyKaVD7uUvukEHTOft7kh00WF9mxAaxZsNs3o/eukbeKuH35jBvQqrT61fzKfAB/Q==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", "cpu": [ "arm" ], @@ -1471,9 +1490,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.3.tgz", - "integrity": "sha512-Sv2GWmrJfRY57urktVLQ0VKZjNZGogVtASAgosDZ1aUB+ykPxSi3X1nWORL5Jk0sTIIwQiPH7iE3BMi9zGWfkg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", "cpu": [ "arm" ], @@ -1485,9 +1504,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.3.tgz", - "integrity": "sha512-FPoJBLsPW2bDNWjSrwNuTPUt30VnfM8GPGRoLCYKZpPx0xiIEdFip3dH6CqgoT0RnoGXptaNziM0WlKgBc+OWQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", "cpu": [ "arm64" ], @@ -1499,9 +1518,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.3.tgz", - "integrity": "sha512-TKxiOvBorYq4sUpA0JT+Fkh+l+G9DScnG5Dqx7wiiqVMiRSkzTclP35pE6eQQYjP4Gc8yEkJGea6rz4qyWhp3g==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", "cpu": [ "arm64" ], @@ -1513,9 +1532,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.3.tgz", - "integrity": "sha512-v2M/mPvVUKVOKITa0oCFksnQQ/TqGrT+yD0184/cWHIu0LoIuYHwox0Pm3ccXEz8cEQDLk6FPKd1CCm+PlsISw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", "cpu": [ "ppc64" ], @@ -1527,9 +1546,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.3.tgz", - "integrity": "sha512-LdrI4Yocb1a/tFVkzmOE5WyYRgEBOyEhWYJe4gsDWDiwnjYKjNs7PS6SGlTDB7maOHF4kxevsuNBl2iOcj3b4A==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", "cpu": [ "riscv64" ], @@ -1541,9 +1560,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.3.tgz", - "integrity": "sha512-d4wVu6SXij/jyiwPvI6C4KxdGzuZOvJ6y9VfrcleHTwo68fl8vZC5ZYHsCVPUi4tndCfMlFniWgwonQ5CUpQcA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", "cpu": [ "s390x" ], @@ -1555,9 +1574,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.3.tgz", - "integrity": "sha512-/6bn6pp1fsCGEY5n3yajmzZQAh+mW4QPItbiWxs69zskBzJuheb3tNynEjL+mKOsUSFK11X4LYF2BwwXnzWleA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", "cpu": [ "x64" ], @@ -1569,9 +1588,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.3.tgz", - "integrity": "sha512-nBXOfJds8OzUT1qUreT/en3eyOXd2EH5b0wr2bVB5999qHdGKkzGzIyKYaKj02lXk6wpN71ltLIaQpu58YFBoQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", "cpu": [ "x64" ], @@ -1583,9 +1602,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.3.tgz", - "integrity": "sha512-ogfbEVQgIZOz5WPWXF2HVb6En+kWzScuxJo/WdQTqEgeyGkaa2ui5sQav9Zkr7bnNCLK48uxmmK0TySm22eiuw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", "cpu": [ "arm64" ], @@ -1597,9 +1616,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.3.tgz", - "integrity": "sha512-ecE36ZBMLINqiTtSNQ1vzWc5pXLQHlf/oqGp/bSbi7iedcjcNb6QbCBNG73Euyy2C+l/fn8qKWEwxr+0SSfs3w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", "cpu": [ "ia32" ], @@ -1611,9 +1630,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.3.tgz", - "integrity": "sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", "cpu": [ "x64" ], @@ -1795,13 +1814,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz", - "integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==", + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@types/unist": { @@ -1818,6 +1837,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/vscode-notebook-renderer": { + "version": "1.72.3", + "resolved": "https://registry.npmjs.org/@types/vscode-notebook-renderer/-/vscode-notebook-renderer-1.72.3.tgz", + "integrity": "sha512-MfmEI3A2McbUV2WaijoTgLOAs9chwHN4WmqOedl3jdtlbzJBWIQ9ZFmQdzPa3lYr5j8DJhRg3KB5AIM/BBfg9Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/web-bluetooth": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", @@ -1826,17 +1852,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz", - "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz", + "integrity": "sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/type-utils": "8.15.0", - "@typescript-eslint/utils": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/type-utils": "8.16.0", + "@typescript-eslint/utils": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1860,16 +1886,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", - "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz", + "integrity": "sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/typescript-estree": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4" }, "engines": { @@ -1889,14 +1915,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz", - "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz", + "integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0" + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1907,14 +1933,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz", - "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz", + "integrity": "sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.15.0", - "@typescript-eslint/utils": "8.15.0", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/utils": "8.16.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1935,9 +1961,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz", - "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz", + "integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==", "dev": true, "license": "MIT", "engines": { @@ -1949,14 +1975,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz", - "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz", + "integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2004,16 +2030,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz", - "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz", + "integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/typescript-estree": "8.15.0" + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2032,13 +2058,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz", - "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz", + "integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/types": "8.16.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2057,46 +2083,36 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-vue": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", - "integrity": "sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", + "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^5.0.0", + "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, + "node_modules/@vscode/codicons": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.36.tgz", + "integrity": "sha512-wsNOvNMMJ2BY8rC2N2MNBG7yOowV3ov8KlvUE/AiVUlHKTfWsw3OgAOQduX7h0Un6GssKD3aoTVH+TF3DSQwKQ==", + "license": "CC-BY-4.0" + }, "node_modules/@vscode/python-extension": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@vscode/python-extension/-/python-extension-1.0.5.tgz", "integrity": "sha512-uYhXUrL/gn92mfqhjAwH2+yGOpjloBxj9ekoL4BhUsKcyJMpEg6WlNf3S3si+5x9zlbHHe7FYQNjZEbz1ymI9Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=16.17.1", "vscode": "^1.78.0" } }, - "node_modules/@vscode/test-electron": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz", - "integrity": "sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "jszip": "^3.10.1", - "ora": "^7.0.1", - "semver": "^7.6.2" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@vscode/vsce": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.2.1.tgz", @@ -2339,23 +2355,23 @@ } }, "node_modules/@vue/devtools-api": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.6.4.tgz", - "integrity": "sha512-5AaJ5ELBIuevmFMZYYLuOO9HUuY/6OlkOELHE7oeDhy4XD/hSODIzktlsvBOsn+bto3aD0psj36LGzwVu5Ip8w==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.6.5.tgz", + "integrity": "sha512-HHvbX7X85k7cqWV6pkcphzlEBbV+kRDzGKumhk9WnDIQuKKw5u2FPvk9icM8v4Wk5VRU1jiMoSFcFBuMqNL6eA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^7.6.4" + "@vue/devtools-kit": "^7.6.5" } }, "node_modules/@vue/devtools-kit": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.6.4.tgz", - "integrity": "sha512-Zs86qIXXM9icU0PiGY09PQCle4TI750IPLmAJzW5Kf9n9t5HzSYf6Rz6fyzSwmfMPiR51SUKJh9sXVZu78h2QA==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.6.5.tgz", + "integrity": "sha512-fLQhUwmUbtEDHW1SEiHUF5k2Ptw816As5ZUVb/SzrqkrJzXI8xjEIo8suNBe/N+ewdz/9m5ayeFH8fmcVIbr4Q==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^7.6.4", + "@vue/devtools-shared": "^7.6.5", "birpc": "^0.2.19", "hookable": "^5.5.3", "mitt": "^3.0.1", @@ -2365,9 +2381,9 @@ } }, "node_modules/@vue/devtools-shared": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.6.4.tgz", - "integrity": "sha512-nD6CUvBEel+y7zpyorjiUocy0nh77DThZJ0k1GRnJeOmY3ATq2fWijEp7wk37gb023Cb0R396uYh5qMSBQ5WFg==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.6.5.tgz", + "integrity": "sha512-szsXQ0jlpjuFfmxb6F40qkSF4gtLC1W+dKRh/UiTulC+RekZsjqcN/qnVFkzqOO1YnzzShinZwfmv+MbfPJnpw==", "dev": true, "license": "MIT", "dependencies": { @@ -2430,15 +2446,15 @@ "license": "MIT" }, "node_modules/@vueuse/core": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.2.0.tgz", - "integrity": "sha512-JIUwRcOqOWzcdu1dGlfW04kaJhW3EXnnjJJfLTtddJanymTL7lF1C0+dVVZ/siLfc73mWn+cGP1PE1PKPruRSA==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.3.0.tgz", + "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==", "dev": true, "license": "MIT", "dependencies": { "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "11.2.0", - "@vueuse/shared": "11.2.0", + "@vueuse/metadata": "11.3.0", + "@vueuse/shared": "11.3.0", "vue-demi": ">=0.14.10" }, "funding": { @@ -2473,14 +2489,14 @@ } }, "node_modules/@vueuse/integrations": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-11.2.0.tgz", - "integrity": "sha512-zGXz3dsxNHKwiD9jPMvR3DAxQEOV6VWIEYTGVSB9PNpk4pTWR+pXrHz9gvXWcP2sTk3W2oqqS6KwWDdntUvNVA==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-11.3.0.tgz", + "integrity": "sha512-5fzRl0apQWrDezmobchoiGTkGw238VWESxZHazfhP3RM7pDSiyXy18QbfYkILoYNTd23HPAfQTJpkUc5QbkwTw==", "dev": true, "license": "MIT", "dependencies": { - "@vueuse/core": "11.2.0", - "@vueuse/shared": "11.2.0", + "@vueuse/core": "11.3.0", + "@vueuse/shared": "11.3.0", "vue-demi": ">=0.14.10" }, "funding": { @@ -2567,9 +2583,9 @@ } }, "node_modules/@vueuse/metadata": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.2.0.tgz", - "integrity": "sha512-L0ZmtRmNx+ZW95DmrgD6vn484gSpVeRbgpWevFKXwqqQxW9hnSi2Ppuh2BzMjnbv4aJRiIw8tQatXT9uOB23dQ==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.3.0.tgz", + "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==", "dev": true, "license": "MIT", "funding": { @@ -2577,9 +2593,9 @@ } }, "node_modules/@vueuse/shared": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.2.0.tgz", - "integrity": "sha512-VxFjie0EanOudYSgMErxXfq6fo8vhr5ICI+BuE3I9FnX7ePllEsVrRQ7O6Q1TLgApeLuPKcHQxAXpP+KnlrJsg==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.3.0.tgz", + "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==", "dev": true, "license": "MIT", "dependencies": { @@ -2982,7 +2998,8 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/birpc": { "version": "0.2.19", @@ -2995,32 +3012,18 @@ } }, "node_modules/bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "buffer": "^6.0.3", + "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -3087,9 +3090,9 @@ } }, "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -3106,9 +3109,10 @@ } ], "license": "MIT", + "optional": true, "dependencies": { "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "ieee754": "^1.1.13" } }, "node_modules/buffer-crc32": { @@ -3167,9 +3171,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001680", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", - "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", + "version": "1.0.30001684", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", + "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", "dev": true, "funding": [ { @@ -3306,35 +3310,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cockatiel": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", @@ -3419,13 +3394,6 @@ "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3685,9 +3653,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.63", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", - "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", + "version": "1.5.65", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.65.tgz", + "integrity": "sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==", "dev": true, "license": "ISC", "peer": true @@ -4856,7 +4824,8 @@ "url": "https://feross.org/support" } ], - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "optional": true }, "node_modules/ignore": { "version": "5.3.2", @@ -4868,13 +4837,6 @@ "node": ">= 4" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true, - "license": "MIT" - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4907,7 +4869,8 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/ini": { "version": "1.3.8", @@ -4989,19 +4952,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5012,19 +4962,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-what": { "version": "4.1.16", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", @@ -5051,13 +4988,6 @@ "node": ">=8" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5232,19 +5162,6 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, "node_modules/juice": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/juice/-/juice-8.1.0.tgz", @@ -5494,16 +5411,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -5597,36 +5504,6 @@ "dev": true, "license": "MIT" }, - "node_modules/log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5641,9 +5518,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.13", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", - "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", + "version": "0.30.14", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", + "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", "dev": true, "license": "MIT", "dependencies": { @@ -5928,16 +5805,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -5987,9 +5854,9 @@ } }, "node_modules/minisearch": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.0.tgz", - "integrity": "sha512-tv7c/uefWdEhcu6hvrfTihflgeEi2tN6VV7HJnCjK6VxM75QQJh4t9FwJCsA2EsRS8LCnu3W87CuGPWMocOLCA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.1.tgz", + "integrity": "sha512-b3YZEYCEH4EdCAtYP7OlDyx7FdPwNzuNwLQ34SfJpM9dlbBZzeXndGavTrC+VCiRWomL21SWfMc6SCKO/U2ZNw==", "dev": true, "license": "MIT" }, @@ -6030,9 +5897,9 @@ "license": "ISC" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { @@ -6159,22 +6026,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/oniguruma-to-es": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-0.4.1.tgz", @@ -6223,68 +6074,6 @@ "node": ">= 0.8.0" } }, - "node_modules/ora": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", - "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^4.0.0", - "cli-spinners": "^2.9.0", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.3.0", - "log-symbols": "^5.1.0", - "stdin-discarder": "^0.1.0", - "string-width": "^6.1.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/ora/node_modules/string-width": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", - "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^10.2.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ovsx": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.1.tgz", @@ -6361,13 +6150,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6552,9 +6334,9 @@ } }, "node_modules/preact": { - "version": "10.24.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", - "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", + "version": "10.25.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.25.0.tgz", + "integrity": "sha512-6bYnzlLxXV3OSpUxLdaxBmE7PMOu0aR3pG6lryK/0jmvcDFPlcXGQAt5DpK3RITWiDrfYZRI0druyaK/S9kYLg==", "dev": true, "license": "MIT", "funding": { @@ -6601,9 +6383,9 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", + "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true, "license": "MIT", "bin": { @@ -6629,13 +6411,6 @@ "node": ">=6.0.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, "node_modules/property-information": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", @@ -6769,28 +6544,21 @@ } }, "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/regex": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/regex/-/regex-5.0.2.tgz", @@ -6802,9 +6570,9 @@ } }, "node_modules/regex-recursion": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-4.2.1.tgz", - "integrity": "sha512-QHNZyZAeKdndD1G3bKAbBEKOSSK4KOHQrAJ01N1LJeb0SoH4DJIeFhp0uUpETgONifS4+P3sOgoA1dhzgrQvhA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-4.3.0.tgz", + "integrity": "sha512-5LcLnizwjcQ2ALfOj95MjcatxyqF5RPySx9yT+PaXu3Gox2vyAtLDjHB8NTJLtMGkvyau6nI3CfpwFCjPUIs/A==", "dev": true, "license": "MIT", "dependencies": { @@ -6828,30 +6596,6 @@ "node": ">=4" } }, - "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -6870,14 +6614,10 @@ "dev": true, "license": "MIT" }, - "node_modules/robotcode": { - "resolved": "", - "link": true - }, "node_modules/rollup": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.3.tgz", - "integrity": "sha512-SLsCOnlmGt9VoZ9Ek8yBK8tAdmPHeppkw+Xa7yDlCEhDTvwYei03JlWo1fdc7YTfLZ4tD8riJCUyAgTbszk1fQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", "dev": true, "license": "MIT", "dependencies": { @@ -6891,24 +6631,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.27.3", - "@rollup/rollup-android-arm64": "4.27.3", - "@rollup/rollup-darwin-arm64": "4.27.3", - "@rollup/rollup-darwin-x64": "4.27.3", - "@rollup/rollup-freebsd-arm64": "4.27.3", - "@rollup/rollup-freebsd-x64": "4.27.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.27.3", - "@rollup/rollup-linux-arm-musleabihf": "4.27.3", - "@rollup/rollup-linux-arm64-gnu": "4.27.3", - "@rollup/rollup-linux-arm64-musl": "4.27.3", - "@rollup/rollup-linux-powerpc64le-gnu": "4.27.3", - "@rollup/rollup-linux-riscv64-gnu": "4.27.3", - "@rollup/rollup-linux-s390x-gnu": "4.27.3", - "@rollup/rollup-linux-x64-gnu": "4.27.3", - "@rollup/rollup-linux-x64-musl": "4.27.3", - "@rollup/rollup-win32-arm64-msvc": "4.27.3", - "@rollup/rollup-win32-ia32-msvc": "4.27.3", - "@rollup/rollup-win32-x64-msvc": "4.27.3", + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", "fsevents": "~2.3.2" } }, @@ -7054,13 +6794,6 @@ "node": ">= 0.4" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true, - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7286,22 +7019,6 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/stdin-discarder": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", - "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stoppable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", @@ -7314,22 +7031,16 @@ } }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -7564,61 +7275,6 @@ "node": ">=6" } }, - "node_modules/tar-stream/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/tar-stream/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/terser": { "version": "5.36.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", @@ -7725,9 +7381,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", - "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.2.tgz", + "integrity": "sha512-ZF5gQIQa/UmzfvxbHZI3JXN0/Jt+vnAfAviNRAMc491laiK6YCLpCW9ft8oaCRFOTxCZtUTE6XB0ZQAe3olntw==", "dev": true, "license": "MIT", "engines": { @@ -7891,9 +7547,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -7905,15 +7561,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.15.0.tgz", - "integrity": "sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.16.0.tgz", + "integrity": "sha512-wDkVmlY6O2do4V+lZd0GtRfbtXbeD0q9WygwXXSJnC1xorE8eqyC2L1tJimqpSeFrOzRlYtWnUp/uzgHQOgfBQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.15.0", - "@typescript-eslint/parser": "8.15.0", - "@typescript-eslint/utils": "8.15.0" + "@typescript-eslint/eslint-plugin": "8.16.0", + "@typescript-eslint/parser": "8.16.0", + "@typescript-eslint/utils": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7956,9 +7612,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" }, @@ -8098,7 +7754,8 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/uuid": { "version": "8.3.2", diff --git a/package.json b/package.json index 75f94479..54a085da 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "qna": "https://github.com/robotcodedev/robotcode/discussions/categories/q-a", "engines": { - "vscode": "^1.86.0" + "vscode": "^1.90.0" }, "categories": [ "Programming Languages", @@ -86,14 +86,215 @@ "notebooks": [ { "type": "robotframework-repl", - "displayName": "RobotFramework REPL", + "displayName": "Robot Framework Notebook", "selector": [ { - "filenamePattern": "*.robotnb" + "filenamePattern": "*.robotbook" } ] } ], + "notebookRenderer": [ + { + "id": "robotframework-repl-html", + "displayName": "Robot Framework Html Log", + "entrypoint": "./out/rendererHtml.js", + "mimeTypes": [ + "x-application/robotframework-repl-html" + ] + }, + { + "id": "robotframework-repl-log", + "displayName": "Robot Framework Log", + "entrypoint": "./out/rendererLog.js", + "mimeTypes": [ + "x-application/robotframework-repl-log" + ], + "requiresMessaging": "optional" + } + ], + "colors": [ + { + "id": "robotcode.logForeground", + "description": "Background color for log.", + "defaults": { + "dark": "editor.foreground", + "light": "editor.foreground", + "highContrast": "editor.foreground", + "highContrastLight": "editor.foreground" + } + }, + { + "id": "robotcode.logBackground", + "description": "Background color for log.", + "defaults": { + "dark": "editor.background", + "light": "editor.background", + "highContrast": "editor.background", + "highContrastLight": "editor.background" + } + }, + { + "id": "robotcode.logLabelForeground", + "description": "Foreground color for label.", + "defaults": { + "dark": "#000000", + "light": "#000000", + "highContrast": "#010203", + "highContrastLight": "#feedc3" + } + }, + { + "id": "robotcode.logLabelBackground", + "description": "Background color for label", + "defaults": { + "dark": "#bbbbbb", + "light": "#bbbbbb", + "highContrast": "#feedc3", + "highContrastLight": "#010203" + } + }, + { + "id": "robotcode.logLabelPassForeground", + "description": "Foreground color for pass label.", + "defaults": { + "dark": "#000000", + "light": "#000000", + "highContrast": "#010203", + "highContrastLight": "#feedc3" + } + }, + { + "id": "robotcode.logLabelPassBackground", + "description": "Background color for pass label.", + "defaults": { + "dark": "#97bd61", + "light": "#97bd61", + "highContrast": "#feedc3", + "highContrastLight": "#010203" + } + }, + { + "id": "robotcode.logLabelWarnForeground", + "description": "Forground color for warn label.", + "defaults": { + "dark": "#000000", + "light": "#000000", + "highContrast": "#010203", + "highContrastLight": "#feedc3" + } + }, + { + "id": "robotcode.logLabelWarnBackground", + "description": "Background color for warn label.", + "defaults": { + "dark": "#fed84f", + "light": "#fed84f", + "highContrast": "#feedc3", + "highContrastLight": "#010203" + } + }, + { + "id": "robotcode.logLabelErrorForeground", + "description": "Background color for error label.", + "defaults": { + "dark": "#ffffff", + "light": "#ffffff", + "highContrast": "#010203", + "highContrastLight": "#feedc3" + } + }, + { + "id": "robotcode.logLabelErrorBackground", + "description": "Foreground color for error label.", + "defaults": { + "dark": "#ce3e01", + "light": "#ce3e01", + "highContrast": "#feedc3", + "highContrastLight": "#010203" + } + }, + { + "id": "robotcode.expanderIconForeground", + "description": "Foreground color of expander icon.", + "defaults": { + "dark": "icon.foreground", + "light": "icon.foreground", + "highContrast": "icon.foreground", + "highContrastLight": "icon.foreground" + } + }, + { + "id": "robotcode.expanderIconHoverBackground", + "description": "Hover Background color of expander icon.", + "defaults": { + "dark": "toolbar.hoverBackground", + "light": "toolbar.hoverBackground", + "highContrast": "toolbar.hoverBackground", + "highContrastLight": "toolbar.hoverBackground" + } + }, + { + "id": "robotcode.expanderIconHoverOutline", + "description": "Hover Outline color of expander icon.", + "defaults": { + "dark": "toolbar.hoverOutline", + "light": "toolbar.hoverOutline", + "highContrast": "toolbar.hoverOutline", + "highContrastLight": "toolbar.hoverOutline" + } + }, + { + "id": "robotcode.expanderHeaderHoverBackground", + "description": "Hover Background color of expander header.", + "defaults": { + "dark": "toolbar.hoverBackground", + "light": "toolbar.hoverBackground", + "highContrast": "toolbar.hoverBackground", + "highContrastLight": "toolbar.hoverBackground" + } + }, + { + "id": "robotcode.expanderHeaderHoverOutline", + "description": "Hover Outline color of expander header.", + "defaults": { + "dark": "toolbar.hoverOutline", + "light": "toolbar.hoverOutline", + "highContrast": "toolbar.hoverOutline", + "highContrastLight": "toolbar.hoverOutline" + } + }, + { + "id": "robotcode.expanderHeaderFocusForeground", + "description": "Hover Background color of expander icon.", + "defaults": { + "dark": "list.focusForeground", + "light": "list.focusForeground", + "highContrast": "list.focusForeground", + "highContrastLight": "list.focusForeground" + } + }, + { + "id": "robotcode.expanderHeaderFocusBackground", + "description": "Hover Background color of expander icon.", + "defaults": { + "dark": "list.focusBackground", + "light": "list.focusBackground", + "highContrast": "list.focusBackground", + "highContrastLight": "list.focusBackground" + } + }, + { + "id": "robotcode.expanderHeaderFocusOutline", + "description": "Hover Background color of expander icon.", + "defaults": { + "dark": "list.focusOutline", + "light": "list.focusOutline", + "highContrast": "list.focusOutline", + "highContrastLight": "list.focusOutline" + } + } + ], "markdown.markdownItPlugins": true, "icons": { "robotcode-robot": { @@ -1136,6 +1337,12 @@ "shortTitle": "Robot Framework File", "category": "RobotCode", "command": "robotcode.createNewFile" + }, + { + "title": "Create New File", + "shortTitle": "Robot Framework Notebook", + "category": "RobotCode", + "command": "robotcode.createNewNotebook" } ], "menus": { @@ -1191,6 +1398,11 @@ "command": "robotcode.createNewFile", "group": "file", "when": "!virtualWorkspace" + }, + { + "command": "robotcode.createNewNotebook", + "group": "notebook", + "when": "!virtualWorkspace" } ] }, @@ -1667,14 +1879,9 @@ ] }, "scripts": { - "vscode:prepublish": "npm run esbuild-base -- --minify", - "esbuild-base": "esbuild ./vscode-client/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node", - "esbuild": "npm run esbuild-base -- --sourcemap", - "esbuild-watch": "npm run esbuild-base -- --sourcemap --watch", - "test-compile": "tsc -p ./", - "compile": "tsc -p ./", - "watch": "tsc -watch -p ./", - "pretest": "npm run compile && npm run lint", + "compile": "node esbuild.mjs", + "vscode:prepublish": "npm run package", + "package": "node esbuild.mjs --production", "lint": "eslint .", "lint-fix": "eslint --fix .", "test": "node ./out/test/runTest.js", @@ -1688,33 +1895,35 @@ "ms-python.debugpy" ], "dependencies": { - "@vscode/python-extension": "^1.0.5", "ansi-colors": "^4.1.3", "fs-extra": "^11.2.0", - "robotcode": "file:", "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@eslint/compat": "^1.2.3", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.15.0", + "@jgoz/esbuild-plugin-typecheck": "^4.0.2", "@types/fs-extra": "^11.0.4", "@types/node": "^22.9.1", - "@types/vscode": "^1.86.0", - "@vscode/test-electron": "^2.4.1", + "@types/vscode": "^1.90.0", + "@types/vscode-notebook-renderer": "^1.72.3", + "@vscode/python-extension": "^1.0.5", "@vscode/vsce": "^3.2.1", + "@vscode/codicons": "^0.0.36", "esbuild": "^0.24.0", "eslint": "^9.15.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", "globals": "^15.12.0", "ovsx": "^0.10.1", - "prettier": "^3.3.3", + "preact": "^10.25.0", + "prettier": "^3.4.1", "ts-loader": "^9.5.1", - "typescript": "^5.6.3", - "typescript-eslint": "^8.15.0" + "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0" }, "workspaces": [ "docs" ] -} +} \ No newline at end of file diff --git a/packages/core/src/robotcode/core/concurrent.py b/packages/core/src/robotcode/core/concurrent.py index 9695527b..55c3624d 100644 --- a/packages/core/src/robotcode/core/concurrent.py +++ b/packages/core/src/robotcode/core/concurrent.py @@ -251,8 +251,8 @@ def run_as_debugpy_hidden_task(callable: Callable[_P, _TResult], *args: _P.args, hide = hidden_tasks == "0" if hide: - thread.pydev_do_not_trace = True # type: ignore[attr-defined] - thread.is_pydev_daemon_thread = True # type: ignore[attr-defined] + setattr(thread, "pydev_do_not_trace", True) + setattr(thread, "is_pydev_daemon_thread", True) thread.start() diff --git a/packages/core/src/robotcode/core/utils/dataclasses.py b/packages/core/src/robotcode/core/utils/dataclasses.py index 62ad3123..03e3f5d7 100644 --- a/packages/core/src/robotcode/core/utils/dataclasses.py +++ b/packages/core/src/robotcode/core/utils/dataclasses.py @@ -190,6 +190,7 @@ def as_json(obj: Any, indent: Optional[bool] = None, compact: Optional[bool] = N default=_default, indent=4 if indent else None, separators=(",", ":") if compact else None, + ensure_ascii=False, ) diff --git a/packages/debugger/src/robotcode/debugger/run.py b/packages/debugger/src/robotcode/debugger/run.py index 6016439f..88803011 100644 --- a/packages/debugger/src/robotcode/debugger/run.py +++ b/packages/debugger/src/robotcode/debugger/run.py @@ -75,13 +75,6 @@ async def _debug_adapter_server_async( ) -> None: from .server import DebugAdapterServer - hidden_tasks = os.environ.get("ROBOTCODE_DISABLE_HIDDEN_TASKS", "0") - hide = hidden_tasks == "0" - - if hide: - current_thread = threading.current_thread - setattr(current_thread, "pydev_do_not_trace", True) - async with DebugAdapterServer( mode=mode, tcp_params=TcpParams(addresses or "127.0.0.1", port), @@ -93,7 +86,7 @@ async def _debug_adapter_server_async( await server.serve() -def _debug_adapter_server_( +def _debug_adapter_server( on_config_done_callback: Optional[Callable[["DebugAdapterServer"], None]], mode: ServerMode, addresses: Union[str, Sequence[str], None], @@ -186,7 +179,7 @@ def run_debugger( app.verbose("Start robotcode debugger thread") run_as_debugpy_hidden_task( - _debug_adapter_server_, + _debug_adapter_server, config_done_callback, mode, addresses, diff --git a/packages/jsonrpc2/src/robotcode/jsonrpc2/server.py b/packages/jsonrpc2/src/robotcode/jsonrpc2/server.py index 85880393..8928294e 100644 --- a/packages/jsonrpc2/src/robotcode/jsonrpc2/server.py +++ b/packages/jsonrpc2/src/robotcode/jsonrpc2/server.py @@ -85,7 +85,7 @@ def start(self) -> None: elif self.mode == ServerMode.TCP: self.loop.run_until_complete(self.start_tcp(self.tcp_params.host, self.tcp_params.port)) elif self.mode == ServerMode.PIPE: - self.start_pipe(self.pipe_name) + self.loop.run_until_complete(self.start_pipe(self.pipe_name)) elif self.mode == ServerMode.PIPE_SERVER: self.loop.run_until_complete(self.start_pipe_server(self.pipe_name)) elif self.mode == ServerMode.SOCKET: @@ -212,7 +212,7 @@ async def start_tcp(self, host: Union[str, Sequence[str], None] = None, port: in self._run_func = self.loop.run_forever @_logger.call - def start_pipe(self, pipe_name: Optional[str]) -> None: + async def start_pipe(self, pipe_name: Optional[str]) -> None: from typing import TYPE_CHECKING if pipe_name is None: @@ -227,15 +227,14 @@ def start_pipe(self, pipe_name: Optional[str]) -> None: if TYPE_CHECKING: from asyncio.windows_events import ProactorEventLoop - self.loop.run_until_complete( - cast("ProactorEventLoop", self.loop).create_pipe_connection( - lambda: cast( - "asyncio.StreamReaderProtocol", - self.create_protocol(), - ), - pipe_name, - ) + await cast("ProactorEventLoop", self.loop).create_pipe_connection( + lambda: cast( + "asyncio.StreamReaderProtocol", + self.create_protocol(), + ), + pipe_name, ) + else: self.loop.run_until_complete(self.loop.create_unix_connection(self.create_protocol, pipe_name)) except NotImplementedError as e: diff --git a/packages/repl/README.md b/packages/repl/README.md index 5d826701..6ddb304d 100644 --- a/packages/repl/README.md +++ b/packages/repl/README.md @@ -8,7 +8,8 @@ ## Introduction -Some classes for [RobotCode](https://robotcode.io) plugin management +Provides a REPL for [RobotCode](https://robotcode.io). + ## Installation diff --git a/packages/repl/pyproject.toml b/packages/repl/pyproject.toml index f85a9bb2..3c803265 100644 --- a/packages/repl/pyproject.toml +++ b/packages/repl/pyproject.toml @@ -27,7 +27,6 @@ classifiers = [ ] dynamic = ["version"] dependencies = [ - "robotcode-jsonrpc2==0.99.0", "robotcode-runner==0.99.0" ] diff --git a/packages/repl/src/robotcode/repl/interpreter.py b/packages/repl/src/robotcode/repl/base_interpreter.py similarity index 54% rename from packages/repl/src/robotcode/repl/interpreter.py rename to packages/repl/src/robotcode/repl/base_interpreter.py index 27202f7c..8c73b392 100644 --- a/packages/repl/src/robotcode/repl/interpreter.py +++ b/packages/repl/src/robotcode/repl/base_interpreter.py @@ -1,8 +1,8 @@ -import sys +import abc +from datetime import datetime from pathlib import Path from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Tuple, Union, cast -import click from robot.api import get_model from robot.errors import ExecutionStatus from robot.output import LOGGER @@ -11,7 +11,7 @@ from robot.running.context import EXECUTION_CONTEXTS from robot.running.signalhandler import _StopSignalMonitor -from robotcode.plugin import Application +from robotcode.core.utils.path import normalized_path from robotcode.robot.utils import get_robot_version from robotcode.robot.utils.ast import iter_nodes @@ -46,26 +46,21 @@ def _run_keyword(kw: Keyword, context: Any) -> Any: return kw.run(context) -TRUE_STRINGS = {"TRUE", "YES", "ON", "1"} - - -def is_true(value: Union[str, bool]) -> bool: - if isinstance(value, str): - return value.upper() in TRUE_STRINGS - return bool(value) - - if get_robot_version() < (7, 0): class InterpreterLogger: - def __init__(self, interpreter: "Interpreter") -> None: + def __init__(self, interpreter: "BaseInterpreter") -> None: self.interpreter = interpreter self.enabled = False def log_message(self, message: OutputMessage) -> None: + if not self.enabled: + return self.interpreter.log_message(message.message, message.level, message.html, message.timestamp) def message(self, message: OutputMessage) -> None: + if not self.enabled: + return self.interpreter.message(message.message, message.level, message.html, message.timestamp) def start_keyword(self, args: Any) -> None: @@ -82,14 +77,18 @@ def end_keyword(self, args: Any) -> None: import robot.output.loggerapi # pyright: ignore[reportMissingImports] class InterpreterLogger(robot.output.loggerapi.LoggerApi): # type: ignore[no-redef] - def __init__(self, interpreter: "Interpreter") -> None: + def __init__(self, interpreter: "BaseInterpreter") -> None: self.interpreter = interpreter self.enabled = False def log_message(self, message: OutputMessage) -> None: + if not self.enabled: + return self.interpreter.log_message(message.message, message.level, message.html, message.timestamp) def message(self, message: OutputMessage) -> None: + if not self.enabled: + return self.interpreter.message(message.message, message.level, message.html, message.timestamp) def start_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: @@ -102,28 +101,26 @@ def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None return self.interpreter.end_keyword(data, result) + def start_body_item(self, data: "running.Keyword", result: "result.Keyword") -> None: + if not self.enabled: + return + self.interpreter.start_keyword(data, result) -class Interpreter: - def __init__( - self, - app: Optional[Application], - files: Optional[List[Path]] = None, - show_keywords: bool = False, - inspect: Optional[bool] = False, - ) -> None: - _patch() + def end_body_item(self, data: "running.Keyword", result: "result.Keyword") -> None: + if not self.enabled: + return + self.interpreter.end_keyword(data, result) - self.app = app - self.files = files - self.show_keywords = show_keywords - self.inspect = inspect - self.executed_files: List[Path] = [] +class BaseInterpreter(abc.ABC): + def __init__(self) -> None: + _patch() self._logger = InterpreterLogger(self) LOGGER.register_logger(self._logger) - + self.last_result: Any = None self.indent = 0 + self.source: Optional[Path] = None def check_for_errors(self, node: Any) -> List[str]: if hasattr(node, "tokens"): @@ -145,7 +142,9 @@ def get_test_body_from_string(self, command: str) -> Tuple[TestCase, List[str]]: + ("\n ".join(command.split("\n")) if "\n" in command else command) ) + "\n" - model = get_model(suite_str) + curdir = normalized_path(self.source).parent if self.source is not None else Path.cwd() + + model = get_model(suite_str, curdir=str(curdir).replace("\\", "\\\\")) suite: TestSuite = TestSuite.from_model(model) errors: List[str] = [] @@ -155,80 +154,39 @@ def get_test_body_from_string(self, command: str) -> Tuple[TestCase, List[str]]: return cast(TestCase, suite.tests[0]), errors - def get_input(self) -> Iterator[Optional[Keyword]]: - if self.executed_files and not self.files and not self.inspect: - raise EOFError - - if self.files: - file = self.files.pop(0) - - self.executed_files.append(file) - - text = file.read_text(encoding="utf-8") - - test, errors = self.get_test_body_from_string(text) - if errors: - return - - for kw in test.body: - yield kw - else: - - lines: List[str] = [] - last_one = False - while True: - - prompt = "" - if sys.stdin.isatty(): - prompt = ">>> " if not lines else "... " - - try: - text = input(prompt) - if len(lines) == 0 and text == "": - break - except KeyboardInterrupt: - if len(lines) > 0: - lines = [] - last_one = False - continue - raise - - lines.append(text) - - test, errors = self.get_test_body_from_string("\n".join(lines)) - - if len(lines) > 1 and lines[-1] == "" and text == "": - last_one = True - - if errors: - if not last_one: - continue - - for kw in test.body: - yield kw - - break + @abc.abstractmethod + def get_input(self) -> Iterator[Optional[Keyword]]: ... def run_keyword(self, kw: Keyword) -> Any: self.indent = 0 context = EXECUTION_CONTEXTS.current - return _run_keyword(kw, context) + try: + return _run_keyword(kw, context) + except (SystemExit, KeyboardInterrupt): + raise + except ExecutionStatus: + raise + except BaseException as e: + self.log_message(str(e), "ERROR", timestamp=datetime.now()) # noqa: DTZ005 def run(self) -> Any: self._logger.enabled = True has_input = True - while has_input: - try: - self.run_input() - except EOFError: - break - except (SystemExit, KeyboardInterrupt): - break - except ExecutionStatus: - pass - except BaseException as e: - self.log_message(str(e), "ERROR") + try: + while has_input: + try: + self.run_input() + except EOFError: + break + except (SystemExit, KeyboardInterrupt): + break + except ExecutionStatus: + pass + except BaseException as e: + self.log_message(str(e), "ERROR", timestamp=datetime.now()) # noqa: DTZ005 + finally: + self._logger.enabled = False def run_input(self) -> None: for kw in self.get_input(): @@ -237,65 +195,29 @@ def run_input(self) -> None: self.set_last_result(self.run_keyword(kw)) def set_last_result(self, result: Any) -> None: - if result is None: - return - if self.app is not None: - self.app.echo(f"{result}") + self.last_result = result + @abc.abstractmethod def log_message( - self, message: str, level: str, html: Union[str, bool] = False, timestamp: Optional[str] = None - ) -> None: - if self.app is None: - return - - if not self.app.config.verbose and level in ["DEBUG", "TRACE"]: - return - - std_err = level in ["ERROR", "FAIL"] - - if level == "INFO": - level = click.style("INFO", fg="green") - elif level == "WARN": - level = click.style("WARN", fg="yellow") - elif level == "ERROR": - level = click.style("ERROR", fg="red") - elif level == "FAIL": - level = click.style("FAIL", fg="red", bold=True) - elif level == "SKIP": - level = click.style("SKIP", dim=True) - elif level == "DEBUG": - level = click.style("DEBUG", fg="bright_black") - elif level == "TRACE": - level = click.style("TRACE", fg="bright_black", dim=True) - - if is_true(html): - message = f"*HTML*{message}" - - self.app.echo(f"{' '*self.indent}[ {level} ] {message}", file=sys.__stdout__ if std_err else sys.__stderr__) + self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None + ) -> None: ... + @abc.abstractmethod def message( - self, message: str, level: str, html: Union[str, bool] = False, timestamp: Optional[str] = None - ) -> None: - if self.app is not None and self.app.config.verbose: - self.log_message(message, level, html, timestamp) + self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None + ) -> None: ... def start_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: - if not self.show_keywords: - return + pass - if self.app is None: - return + def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: + pass - self.app.echo( - f"{' '*self.indent}KEYWORD {result.libname}.{result.kwname} {' '.join(result.args)}", file=sys.__stdout__ - ) - self.indent += 1 - def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: - if not self.show_keywords: - return +TRUE_STRINGS = {"TRUE", "YES", "ON", "1"} - if self.app is None: - return - self.indent -= 1 +def is_true(value: Union[str, bool]) -> bool: + if isinstance(value, str): + return value.upper() in TRUE_STRINGS + return bool(value) diff --git a/packages/repl/src/robotcode/repl/cli.py b/packages/repl/src/robotcode/repl/cli.py new file mode 100644 index 00000000..7a28d3ef --- /dev/null +++ b/packages/repl/src/robotcode/repl/cli.py @@ -0,0 +1,141 @@ +from pathlib import Path +from typing import Optional, Tuple + +import click + +from robotcode.plugin import Application, pass_application + +from .__version__ import __version__ +from .console_interpreter import ConsoleInterpreter +from .run import run_repl + + +@click.command(add_help_option=True) +@click.option( + "-v", + "--variable", + metavar="name:value", + type=str, + multiple=True, + help="Set variables in the test data. see `robot --variable` option.", +) +@click.option( + "-V", + "--variablefile", + metavar="PATH", + type=str, + multiple=True, + help="Python or YAML file file to read variables from. see `robot --variablefile` option.", +) +@click.option( + "-P", + "--pythonpath", + metavar="PATH", + type=str, + multiple=True, + help="Additional locations where to search test libraries" + " and other extensions when they are imported. see `robot --pythonpath` option.", +) +@click.option( + "-k", + "--show-keywords", + is_flag=True, + default=False, + help="Executed keywords will be shown in the output.", +) +@click.option( + "-i", + "--inspect", + is_flag=True, + default=False, + help="Activate inspection mode. This forces a prompt to appear after the REPL script is executed.", +) +@click.option( + "-d", + "--outputdir", + metavar="DIR", + type=str, + help="Where to create output files. see `robot --outputdir` option.", +) +@click.option( + "-o", + "--output", + metavar="FILE", + type=str, + help="XML output file. see `robot --output` option.", +) +@click.option( + "-r", + "--report", + metavar="FILE", + type=str, + help="HTML output file. see `robot --report` option.", +) +@click.option( + "-l", + "--log", + metavar="FILE", + type=str, + help="HTML log file. see `robot --log` option.", +) +@click.option( + "-x", + "--xunit", + metavar="FILE", + type=str, + help="xUnit output file. see `robot --xunit` option.", +) +@click.option( + "-s", + "--source", + type=click.Path(path_type=Path), + metavar="FILE", + help="Specifies the path to a source file. This file must not exist and will neither be read nor written. " + "It is used solely to set the current working directory for the REPL script " + "and to assign a name to the internal suite.", +) +@click.version_option(version=__version__, prog_name="RobotCode REPL") +@click.argument( + "files", + type=click.Path(exists=True, dir_okay=False, path_type=Path), + nargs=-1, + required=False, +) +@pass_application +def repl( + app: Application, + variable: Tuple[str, ...], + variablefile: Tuple[str, ...], + pythonpath: Tuple[str, ...], + show_keywords: bool, + inspect: bool, + outputdir: Optional[str], + output: Optional[str], + report: Optional[str], + log: Optional[str], + xunit: Optional[str], + source: Optional[Path], + files: Tuple[Path, ...], +) -> None: + """\ + Run Robot Framework interactively. + """ + if files: + files = tuple(f.absolute() for f in files) + + interpreter = ConsoleInterpreter(app, files=list(files), show_keywords=show_keywords, inspect=inspect) + + run_repl( + interpreter=interpreter, + app=app, + variablefile=variable, + variable=variablefile, + pythonpath=pythonpath, + outputdir=outputdir, + output=output, + report=report, + log=log, + xunit=xunit, + source=source, + files=files, + ) diff --git a/packages/repl/src/robotcode/repl/cli/__init__.py b/packages/repl/src/robotcode/repl/cli/__init__.py deleted file mode 100644 index 77f8401c..00000000 --- a/packages/repl/src/robotcode/repl/cli/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .repl import repl - -__all__ = ["repl"] diff --git a/packages/repl/src/robotcode/repl/cli/repl.py b/packages/repl/src/robotcode/repl/cli/repl.py deleted file mode 100644 index a9f55fca..00000000 --- a/packages/repl/src/robotcode/repl/cli/repl.py +++ /dev/null @@ -1,232 +0,0 @@ -import io -import sys -from pathlib import Path -from typing import Optional, Tuple - -import click -from robot.api import TestSuite, get_model -from robot.conf import RobotSettings -from robot.errors import DATA_ERROR, INFO_PRINTED, DataError, Information -from robot.output import LOGGER -from robot.reporting import ResultWriter - -from robotcode.plugin import ( - Application, - pass_application, -) -from robotcode.robot.utils import get_robot_version -from robotcode.runner.cli.robot import RobotFrameworkEx, handle_robot_options - -from ..interpreter import Interpreter -from ..repl_listener import ReplListener - -REPL_SUITE = """\ -*** Settings *** -Library robotcode.repl.Repl -*** Test Cases *** -RobotCode REPL - repl -""" - - -def run_repl( - app: Application, - inspect: bool = False, - variable: Tuple[str, ...] = (), - variablefile: Tuple[str, ...] = (), - pythonpath: Tuple[str, ...] = (), - outputdir: Optional[str] = None, - output: Optional[str] = None, - report: Optional[str] = None, - log: Optional[str] = None, - xunit: Optional[str] = None, - files: Tuple[Path, ...] = (), - show_keywords: bool = False, - interpreter: Optional[Interpreter] = None, -) -> None: - robot_options_and_args: Tuple[str, ...] = () - - if files: - files = tuple(f.absolute() for f in files) - - for var in variable: - robot_options_and_args += ("--variable", var) - for varfile in variablefile: - robot_options_and_args += ("--variablefile", varfile) - for pypath in pythonpath: - robot_options_and_args += ("--pythonpath", pypath) - if outputdir: - robot_options_and_args += ("--outputdir", outputdir) - - root_folder, _profile, cmd_options = handle_robot_options(app, (*robot_options_and_args, *(str(f) for f in files))) - - try: - - options, _ = RobotFrameworkEx( - app, - ["."], - app.config.dry, - root_folder, - ).parse_arguments((*cmd_options, *robot_options_and_args)) - - if interpreter is None: - interpreter = Interpreter(app, files=list(files), show_keywords=show_keywords, inspect=inspect) - - settings = RobotSettings( - options, - console="NONE", - output=output, - log=log, - report=report, - xunit=xunit, - quiet=True, - listener=[ - ReplListener(app, interpreter), - ], - ) - - if app is not None and app.show_diagnostics: - LOGGER.register_console_logger(**settings.console_output_config) - else: - LOGGER.unregister_console_logger() - - if get_robot_version() >= (5, 0): - if settings.pythonpath: - sys.path = settings.pythonpath + sys.path - - with io.StringIO(REPL_SUITE) as suite_io: - model = get_model(suite_io) - - suite = TestSuite.from_model(model) - suite.configure(**settings.suite_config) - result = suite.run(settings) - - if settings.log or settings.report or settings.xunit: - writer = ResultWriter(settings.output if settings.log else result) - writer.write_results(settings.get_rebot_settings()) - - except Information as err: - app.echo(str(err)) - app.exit(INFO_PRINTED) - except DataError as err: - app.error(str(err)) - app.exit(DATA_ERROR) - - -@click.command( - context_settings={"allow_extra_args": True, "ignore_unknown_options": True}, - add_help_option=True, -) -@click.option( - "-v", - "--variable", - metavar="name:value", - type=str, - multiple=True, - help="Set variables in the test data. see `robot --variable` option.", -) -@click.option( - "-V", - "--variablefile", - metavar="PATH", - type=str, - multiple=True, - help="Python or YAML file file to read variables from. see `robot --variablefile` option.", -) -@click.option( - "-P", - "--pythonpath", - metavar="PATH", - type=str, - multiple=True, - help="Additional locations where to search test libraries" - " and other extensions when they are imported. see `robot --pythonpath` option.", -) -@click.option( - "-k", - "--show-keywords", - is_flag=True, - default=False, - help="Executed keywords will be shown in the output.", -) -@click.option( - "-i", - "--inspect", - is_flag=True, - default=False, - help="Activate inspection mode. This forces a prompt to appear after the REPL script is executed.", -) -@click.option( - "-d", - "--outputdir", - metavar="DIR", - type=str, - help="Where to create output files. see `robot --outputdir` option.", -) -@click.option( - "-o", - "--output", - metavar="FILE", - type=str, - help="XML output file. see `robot --output` option.", -) -@click.option( - "-r", - "--report", - metavar="FILE", - type=str, - help="HTML output file. see `robot --report` option.", -) -@click.option( - "-l", - "--log", - metavar="FILE", - type=str, - help="HTML log file. see `robot --log` option.", -) -@click.option( - "-x", - "--xunit", - metavar="FILE", - type=str, - help="xUnit output file. see `robot --xunit` option.", -) -@click.argument( - "files", - type=click.Path(exists=True, dir_okay=False, path_type=Path), - nargs=-1, - required=False, -) -@pass_application -def repl( - app: Application, - variable: Tuple[str, ...], - variablefile: Tuple[str, ...], - pythonpath: Tuple[str, ...], - show_keywords: bool, - inspect: bool, - outputdir: Optional[str], - output: Optional[str], - report: Optional[str], - log: Optional[str], - xunit: Optional[str], - files: Tuple[Path, ...], -) -> None: - """\ - Run Robot Framework interactively. - """ - - run_repl( - app=app, - inspect=inspect, - variablefile=variable, - variable=variablefile, - pythonpath=pythonpath, - outputdir=outputdir, - output=output, - report=report, - log=log, - xunit=xunit, - files=files, - show_keywords=show_keywords, - ) diff --git a/packages/repl/src/robotcode/repl/console_interpreter.py b/packages/repl/src/robotcode/repl/console_interpreter.py new file mode 100644 index 00000000..e735c409 --- /dev/null +++ b/packages/repl/src/robotcode/repl/console_interpreter.py @@ -0,0 +1,142 @@ +import sys +from datetime import datetime +from pathlib import Path +from typing import Iterator, List, Optional, Union + +import click +from robot import result, running +from robot.running import Keyword + +from robotcode.plugin import Application + +from .base_interpreter import BaseInterpreter, is_true + + +class ConsoleInterpreter(BaseInterpreter): + def __init__( + self, + app: Optional[Application], + files: Optional[List[Path]] = None, + show_keywords: bool = False, + inspect: Optional[bool] = False, + ) -> None: + super().__init__() + + self.app = app + self.files = files + self.show_keywords = show_keywords + self.inspect = inspect + + self.executed_files: List[Path] = [] + + def get_input(self) -> Iterator[Optional[Keyword]]: + if self.executed_files and not self.files and not self.inspect: + raise EOFError + + if self.files: + file = self.files.pop(0) + + self.executed_files.append(file) + + text = file.read_text(encoding="utf-8") + + test, errors = self.get_test_body_from_string(text) + if errors: + return + + for kw in test.body: + yield kw + else: + + lines: List[str] = [] + last_one = False + while True: + + prompt = "" + if sys.stdin.isatty(): + prompt = ">>> " if not lines else "... " + + try: + text = input(prompt) + if len(lines) == 0 and text == "": + break + except KeyboardInterrupt: + if len(lines) > 0: + lines = [] + last_one = False + continue + raise + + lines.append(text) + + test, errors = self.get_test_body_from_string("\n".join(lines)) + + if len(lines) > 1 and lines[-1] == "" and text == "": + last_one = True + + if errors: + if not last_one: + continue + + for kw in test.body: + yield kw + + break + + def log_message( + self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None + ) -> None: + if self.app is None: + return + + if not self.app.config.verbose and level in ["DEBUG", "TRACE"]: + return + + std_err = level in ["ERROR", "FAIL"] + + if level == "INFO": + level = click.style("INFO", fg="green") + elif level == "WARN": + level = click.style("WARN", fg="yellow") + elif level == "ERROR": + level = click.style("ERROR", fg="red") + elif level == "FAIL": + level = click.style("FAIL", fg="red", bold=True) + elif level == "SKIP": + level = click.style("SKIP", dim=True) + elif level == "DEBUG": + level = click.style("DEBUG", fg="bright_black") + elif level == "TRACE": + level = click.style("TRACE", fg="bright_black", dim=True) + + if is_true(html): + message = f"*HTML*{message}" + + self.app.echo(f"{' '*self.indent}[ {level} ] {message}", file=sys.__stdout__ if std_err else sys.__stderr__) + + def message( + self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None + ) -> None: + if self.app is not None and self.app.config.verbose: + self.log_message(message, level, html, timestamp) + + def start_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: + if not self.show_keywords: + return + + if self.app is None: + return + + self.app.echo( + f"{' '*self.indent}KEYWORD {result.libname}.{result.kwname} {' '.join(result.args)}", file=sys.__stdout__ + ) + self.indent += 1 + + def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: + if not self.show_keywords: + return + + if self.app is None: + return + + self.indent -= 1 diff --git a/packages/repl/src/robotcode/repl/repl_listener.py b/packages/repl/src/robotcode/repl/repl_listener.py deleted file mode 100644 index 024a1bbd..00000000 --- a/packages/repl/src/robotcode/repl/repl_listener.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Any, ClassVar, Dict, Optional - -from robotcode.plugin import Application - -from .interpreter import Interpreter - - -class ReplListener: - ROBOT_LISTENER_API_VERSION = 2 - instance: ClassVar["ReplListener"] - - def __init__(self, app: Application, interpreter: Optional[Interpreter] = None) -> None: - ReplListener.instance = self - self.app = app - self.interpreter = interpreter or Interpreter(app) - - def start_keyword( - self, - name: str, - attributes: Dict[str, Any], - ) -> None: - if name != "robotcode.repl.Repl.Repl": - return - - self.interpreter.run() diff --git a/packages/repl/src/robotcode/repl/run.py b/packages/repl/src/robotcode/repl/run.py new file mode 100644 index 00000000..9824462e --- /dev/null +++ b/packages/repl/src/robotcode/repl/run.py @@ -0,0 +1,133 @@ +import io +import sys +from pathlib import Path +from typing import Any, ClassVar, Dict, Optional, Tuple + +from robot.api import TestSuite, get_model +from robot.conf import RobotSettings +from robot.errors import DATA_ERROR, INFO_PRINTED, DataError, Information +from robot.output import LOGGER +from robot.reporting import ResultWriter + +from robotcode.core.utils.path import normalized_path +from robotcode.plugin import ( + Application, +) +from robotcode.robot.utils import get_robot_version +from robotcode.runner.cli.robot import RobotFrameworkEx, handle_robot_options + +from .base_interpreter import BaseInterpreter + +REPL_SUITE = """\ +*** Settings *** +Library robotcode.repl.Repl +*** Test Cases *** +RobotCode REPL + repl +""" + + +class ReplListener: + ROBOT_LISTENER_API_VERSION = 2 + instance: ClassVar["ReplListener"] + + def __init__(self, app: Application, interpreter: BaseInterpreter) -> None: + ReplListener.instance = self + self.app = app + self.interpreter = interpreter + + def start_keyword( + self, + name: str, + attributes: Dict[str, Any], + ) -> None: + if name != "robotcode.repl.Repl.Repl": + return + + self.interpreter.run() + + +def run_repl( + interpreter: BaseInterpreter, + app: Application, + variable: Tuple[str, ...] = (), + variablefile: Tuple[str, ...] = (), + pythonpath: Tuple[str, ...] = (), + outputdir: Optional[str] = None, + output: Optional[str] = None, + report: Optional[str] = None, + log: Optional[str] = None, + xunit: Optional[str] = None, + source: Optional[Path] = None, + files: Tuple[Path, ...] = (), +) -> None: + robot_options_and_args: Tuple[str, ...] = () + + if files: + files = tuple(f.absolute() for f in files) + + for var in variable: + robot_options_and_args += ("--variable", var) + for varfile in variablefile: + robot_options_and_args += ("--variablefile", varfile) + for pypath in pythonpath: + robot_options_and_args += ("--pythonpath", pypath) + if outputdir: + robot_options_and_args += ("--outputdir", outputdir) + + root_folder, _profile, cmd_options = handle_robot_options(app, (*robot_options_and_args, *(str(f) for f in files))) + + with app.chdir(root_folder) as orig_folder: + try: + curdir = normalized_path(source).parent if source is not None else Path.cwd() + + options, _ = RobotFrameworkEx( + app, + ["."], + app.config.dry, + root_folder=root_folder, + orig_folder=orig_folder, + ).parse_arguments((*cmd_options, *robot_options_and_args)) + + interpreter.source = source + + settings = RobotSettings( + options, + outputdir=str(curdir), + console="NONE", + output=output, + log=log, + report=report, + xunit=xunit, + quiet=True, + listener=[ + ReplListener(app, interpreter), + ], + ) + + if app is not None and app.show_diagnostics: + LOGGER.register_console_logger(**settings.console_output_config) + else: + LOGGER.unregister_console_logger() + + if get_robot_version() >= (5, 0): + if settings.pythonpath: + sys.path = settings.pythonpath + sys.path + + with io.StringIO(REPL_SUITE) as suite_io: + model = get_model(suite_io, curdir=str(curdir).replace("\\", "\\\\")) + + suite = TestSuite.from_model(model) + suite.configure(**settings.suite_config) + result = suite.run(settings) + + if settings.log or settings.report or settings.xunit: + writer = ResultWriter(settings.output if settings.log else result) + writer.write_results(settings.get_rebot_settings()) + + except Information as err: + app.echo(str(err)) + app.exit(INFO_PRINTED) + except DataError as err: + app.error(str(err)) + app.exit(DATA_ERROR) diff --git a/packages/repl_server/LICENSE.txt b/packages/repl_server/LICENSE.txt new file mode 100644 index 00000000..137069b8 --- /dev/null +++ b/packages/repl_server/LICENSE.txt @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packages/repl_server/README.md b/packages/repl_server/README.md new file mode 100644 index 00000000..2a0be5a0 --- /dev/null +++ b/packages/repl_server/README.md @@ -0,0 +1,21 @@ +# robotcode-repl-server + +[![PyPI - Version](https://img.shields.io/pypi/v/robotcode-repl.svg)](https://pypi.org/project/robotcode-repl-server) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/robotcode-repl.svg)](https://pypi.org/project/robotcode-repl-server) +[![License](https://img.shields.io/github/license/robotcodedev/robotcode?style=flat&logo=apache)](https://github.com/robotcodedev/robotcode/blob/master/LICENSE.txt) + +----- + +## Introduction + +Some classes for [RobotCode](https://robotcode.io) plugin management + +## Installation + +```console +pip install robotcode-repl-server +``` + +## License + +`robotcode-repl-server` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. diff --git a/packages/repl_server/pyproject.toml b/packages/repl_server/pyproject.toml new file mode 100644 index 00000000..e6b37d4a --- /dev/null +++ b/packages/repl_server/pyproject.toml @@ -0,0 +1,60 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "robotcode-repl-server" +description = 'RobotCode REPL Server for Robot Framework' +readme = { "file" = "README.md", "content-type" = "text/markdown" } +requires-python = ">=3.8" +license = {text = "Apache-2.0"} +keywords = [] +authors = [{ name = "Daniel Biehl", email = "dbiehl@live.de" }] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Operating System :: OS Independent", + "Topic :: Utilities", + "Typing :: Typed", + "Framework :: Robot Framework", + "Framework :: Robot Framework :: Tool", +] +dynamic = ["version"] +dependencies = [ + "robotcode-jsonrpc2==0.99.0", + "robotcode-runner==0.99.0" +] + +[project.entry-points.robotcode] +repl_server = "robotcode.repl_server.hooks" + +[project.urls] +Homepage = "https://robotcode.io" +Donate = "https://opencollective.com/robotcode" +Documentation = "https://github.com/robotcodedev/robotcode#readme" +Changelog = "https://github.com/robotcodedev/robotcode/blob/main/CHANGELOG.md" +Issues = "https://github.com/robotcodedev/robotcode/issues" +Source = "https://github.com/robotcodedev/robotcode" + +[tool.hatch.version] +path = "src/robotcode/repl_server/__version__.py" + +[tool.hatch.build] +dev-mode-dirs = ["src"] + +[tool.hatch.build.targets.wheel] +only-include = ["src/robotcode"] +sources = ["src"] + +[tool.hatch.build.targets.sdist] +only-include = ["src"] + +[tool.hatch.envs.build] +detached = true +python = "38" diff --git a/packages/repl_server/src/robotcode/repl_server/__init__.py b/packages/repl_server/src/robotcode/repl_server/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/repl_server/src/robotcode/repl_server/__version__.py b/packages/repl_server/src/robotcode/repl_server/__version__.py new file mode 100644 index 00000000..c0f51b71 --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/__version__.py @@ -0,0 +1 @@ +__version__ = "0.99.0" diff --git a/packages/repl_server/src/robotcode/repl_server/cli.py b/packages/repl_server/src/robotcode/repl_server/cli.py new file mode 100644 index 00000000..085be778 --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/cli.py @@ -0,0 +1,236 @@ +import asyncio +import threading +import time +from pathlib import Path +from typing import Any, Optional, Sequence, Tuple + +import click + +from robotcode.core.concurrent import Task, run_as_debugpy_hidden_task +from robotcode.core.types import ServerMode, TcpParams +from robotcode.plugin import Application, pass_application +from robotcode.plugin.click_helper.options import ( + resolve_server_options, + server_options, +) +from robotcode.plugin.click_helper.types import AddressesPort, add_options +from robotcode.repl.run import run_repl + +from .__version__ import __version__ +from .interpreter import Interpreter +from .server import TCP_DEFAULT_PORT, ReplServer + +REPL_SERVER_DEFAULT_PORT = TCP_DEFAULT_PORT + +_server: Optional[ReplServer] = None +_server_lock = threading.RLock() + + +def get_server() -> Optional["ReplServer"]: + with _server_lock: + return _server + + +def set_server(value: Optional["ReplServer"]) -> None: + with _server_lock: + global _server + _server = value + + +def wait_for_server(task: "Task[Any]", timeout: float = 10) -> "ReplServer": + + start_time = time.monotonic() + while get_server() is None and time.monotonic() - start_time < timeout: + time.sleep(0.005) + + result = get_server() + + if result is None: + task.result(5) + raise RuntimeError("Timeout to get server instance.") + + return result + + +def run_jsonrpc_server_async( + mode: ServerMode, + port: Optional[int], + bind: Optional[Sequence[str]], + pipe_name: Optional[str], + interpreter: Interpreter, +) -> None: + with ReplServer( + interpreter, + ServerMode(mode), + tcp_params=TcpParams(bind or "127.0.0.1", port if port is not None else REPL_SERVER_DEFAULT_PORT), + pipe_name=pipe_name, + ) as server: + set_server(server) + try: + server.run() + finally: + set_server(None) + + +def run_jsonrpc_server( + mode: ServerMode, + port: Optional[int], + bind: Optional[Sequence[str]], + pipe_name: Optional[str], + interpreter: Interpreter, +) -> None: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + run_jsonrpc_server_async(mode, port, bind, pipe_name, interpreter) + + +@click.command( + context_settings={"allow_extra_args": True, "ignore_unknown_options": True}, + add_help_option=True, +) +@add_options(*server_options(ServerMode.STDIO, default_port=REPL_SERVER_DEFAULT_PORT)) +@click.option( + "-v", + "--variable", + metavar="name:value", + type=str, + multiple=True, + help="Set variables in the test data. see `robot --variable` option.", +) +@click.option( + "-V", + "--variablefile", + metavar="PATH", + type=str, + multiple=True, + help="Python or YAML file file to read variables from. see `robot --variablefile` option.", +) +@click.option( + "-P", + "--pythonpath", + metavar="PATH", + type=str, + multiple=True, + help="Additional locations where to search test libraries" + " and other extensions when they are imported. see `robot --pythonpath` option.", +) +@click.option( + "-d", + "--outputdir", + metavar="DIR", + type=str, + help="Where to create output files. see `robot --outputdir` option.", +) +@click.option( + "-o", + "--output", + metavar="FILE", + type=str, + help="XML output file. see `robot --output` option.", +) +@click.option( + "-r", + "--report", + metavar="FILE", + type=str, + help="HTML output file. see `robot --report` option.", +) +@click.option( + "-l", + "--log", + metavar="FILE", + type=str, + help="HTML log file. see `robot --log` option.", +) +@click.option( + "-x", + "--xunit", + metavar="FILE", + type=str, + help="xUnit output file. see `robot --xunit` option.", +) +@click.version_option(version=__version__, prog_name="RobotCode REPL Server") +@click.option( + "-s", + "--source", + type=click.Path(path_type=Path), + metavar="FILE", + help="Specifies the path to a source file. This file must not exist and will neither be read nor written. " + "It is used solely to set the current working directory for the REPL script " + "and to assign a name to the internal suite.", +) +@click.argument( + "files", + type=click.Path(exists=True, dir_okay=False, path_type=Path), + nargs=-1, + required=False, +) +@pass_application +@click.pass_context +def repl_server( + ctx: click.Context, + app: Application, + mode: ServerMode, + port: Optional[int], + bind: Optional[Sequence[str]], + pipe_name: Optional[str], + tcp: Optional[AddressesPort], + socket: Optional[AddressesPort], + stdio: Optional[bool], + pipe: Optional[str], + pipe_server: Optional[str], + variable: Tuple[str, ...], + variablefile: Tuple[str, ...], + pythonpath: Tuple[str, ...], + outputdir: Optional[str], + output: Optional[str], + report: Optional[str], + log: Optional[str], + xunit: Optional[str], + source: Optional[Path], + files: Tuple[Path, ...], +) -> None: + """\ + Run Robot Framework interactively. + """ + + mode, port, bind, pipe_name = resolve_server_options( + ctx, + app, + mode, + port, + bind, + pipe_name, + tcp, + socket, + stdio, + pipe, + pipe_server, + ) + + interpreter = Interpreter(list(files)) + + server_task = run_as_debugpy_hidden_task(run_jsonrpc_server, mode, port, bind, pipe_name, interpreter) + + server = wait_for_server(server_task) + + try: + run_repl( + interpreter=interpreter, + app=app, + variablefile=variable, + variable=variablefile, + pythonpath=pythonpath, + outputdir=outputdir, + output=output, + report=report, + log=log, + xunit=xunit, + source=source, + files=files, + ) + finally: + if server is not None: + server.loop.stop() + + server_task.result(5) diff --git a/packages/repl_server/src/robotcode/repl_server/hooks.py b/packages/repl_server/src/robotcode/repl_server/hooks.py new file mode 100644 index 00000000..d2b87cbd --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/hooks.py @@ -0,0 +1,12 @@ +from typing import List + +import click + +from robotcode.plugin import hookimpl + +from .cli import repl_server + + +@hookimpl +def register_cli_commands() -> List[click.Command]: + return [repl_server] diff --git a/packages/repl_server/src/robotcode/repl_server/html_writer.py b/packages/repl_server/src/robotcode/repl_server/html_writer.py new file mode 100644 index 00000000..aa618ff8 --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/html_writer.py @@ -0,0 +1,324 @@ +from contextlib import contextmanager +from datetime import datetime, timedelta +from typing import Any, Dict, Generator, List, Optional, Sequence, TypeVar, Union + +from robot.utils.robottime import elapsed_time_to_string + +from robotcode.repl.base_interpreter import is_true +from robotcode.robot.utils import get_robot_version + + +class ElementDataBase: + def as_str(self, indent: int = 0) -> str: + raise NotImplementedError + + def __str__(self) -> str: + return self.as_str(0) + + +_T = TypeVar("_T", bound=ElementDataBase) + + +class TextElement(ElementDataBase): + def __init__(self, text: str) -> None: + self.text = text + + def as_str(self, indent: int = 0) -> str: + return f"{' '*indent}{self.text}" + + +class RawElement(ElementDataBase): + def __init__(self, text: str) -> None: + self.text = text + + def as_str(self, indent: int = 0) -> str: + return f"{' '*indent}{self.text}" + + +class Element(ElementDataBase): + def __init__( + self, + tag_name: str, + text: Optional[str] = None, + classes: Optional[List[str]] = None, + styles: Optional[Dict[str, str]] = None, + attributes: Optional[Dict[str, str]] = None, + **kwargs: Any, + ) -> None: + self.tag_name = tag_name + self.classes = classes + self.styles = styles + if attributes is None: + attributes = {} + attributes.update(kwargs) + self.attributes = attributes + self.children: List[ElementDataBase] = [] + + if text is not None: + self.add_element(TextElement(text)) + + def add_element(self, child: _T) -> _T: + self.children.append(child) + return child + + @contextmanager + def tag( + self, + tag_name: str, + *, + text: Optional[str] = None, + classes: Optional[List[str]] = None, + styles: Optional[Dict[str, str]] = None, + attributes: Optional[Dict[str, str]] = None, + **kwargs: Any, + ) -> Generator["Element", None, None]: + element = Element(tag_name, text=text, classes=classes, styles=styles, attributes=attributes, **kwargs) + + yield element + + self.add_element(element) + + def add_raw(self, text: Any) -> None: + self.add_element(RawElement(str(text))) + + def add_text(self, text: Any) -> None: + self.add_element(TextElement(str(text))) + + def _build_attributes(self) -> str: + result = [] + if self.classes: + result.append(f'class="{" ".join(s for s in self.classes if s)}"') + if self.styles: + result.append(f'style="{"; ".join(f"{k}: {v}" for k, v in self.styles.items() if v)}"') + if self.attributes: + result.extend(f'{k}="{v}"' for k, v in self.attributes.items()) + + return " ".join(result) + + NON_BREAKABLE_TAGS = {"span", "a", "b", "i", "u", "strong", "em", "code", "pre", "tt", "samp", "kbd", "var", "td"} + + def as_str(self, indent: int = 0, *, only_children: bool = False) -> str: + if not only_children: + attributes = self._build_attributes() + + if attributes: + start_tag = f"<{self.tag_name} {attributes}>" + else: + start_tag = f"<{self.tag_name}>" + + end_tag = f"" + + result = " " * indent + start_tag + else: + result = "" + end_tag = None + + if self.children: + result += "\n" if self.tag_name not in self.NON_BREAKABLE_TAGS else "" + for child in self.children: + result += child.as_str((indent + 1) if self.tag_name not in self.NON_BREAKABLE_TAGS else 0) + ( + "\n" if self.tag_name not in self.NON_BREAKABLE_TAGS else "" + ) + result += (" " * indent) if self.tag_name not in self.NON_BREAKABLE_TAGS else "" + + if end_tag: + result += end_tag + + return result + + +def create_keyword_html( + id: Optional[str] = None, + name: Optional[str] = "", + owner: Optional[str] = None, + source_name: Optional[str] = None, + doc: Optional[str] = "", + args: Sequence[str] = (), + assign: Sequence[str] = (), + tags: Sequence[str] = (), + timeout: Optional[str] = None, + type: str = "KEYWORD", + status: str = "FAIL", + message: str = "", + start_time: Union[datetime, str, None] = None, + end_time: Union[datetime, str, None] = None, + elapsed_time: Union[timedelta, int, float, None] = None, + shadow_root_id: Optional[str] = None, +) -> Element: + result = Element("div", classes=["keyword"], id=id) + + elapsed_time_str = ( + ( + elapsed_time_to_string(elapsed_time) + if get_robot_version() < (7, 0) + else elapsed_time_to_string(elapsed_time, seconds=True) + ) + if elapsed_time is not None + else "" + ) + + with result.tag( + "div", + classes=["element-header", "closed" if status not in ["FAIL"] else ""], + onclick=f"toggleKeyword('{id}', '{shadow_root_id}')", + ) as e_element_header: + with e_element_header.tag( + "div", + classes=["element-header-left"], + title=f"{type.upper()} {owner}.{name} [{status}]", + ) as e_header_left: + if elapsed_time is not None: + with e_header_left.tag("span", classes=["elapsed"]) as e_elapsed: + e_elapsed.add_text(elapsed_time_str) + with e_header_left.tag("span", classes=["label", status.lower()]) as e_label: + e_label.add_text(str(type).upper()) + with e_header_left.tag("span", classes=["assign"]) as e_assign: + e_assign.add_text(" ".join(assign)) + with e_header_left.tag("span", classes=["name"]) as e_name: + with e_name.tag("span", classes=["parent-name"]) as parent_name: + parent_name.add_text((owner + " . ") if owner else "") + e_name.add_text(name) + e_header_left.add_raw(" ") + with e_header_left.tag("span", classes=["arg"]) as args_tag: + args_tag.add_text(" ".join(args)) + with e_element_header.tag("div", classes=["element-header-right"]) as e_header_right: + with e_header_right.tag( + "div", + classes=["expand"], + title="Expand all", + onclick=f"expandAll(event, '{id}', '{shadow_root_id}')", + ): + pass + with e_header_right.tag( + "div", + classes=["collapse"], + title="Collapse all", + onclick=f"collapseAll(event, '{id}', '{shadow_root_id}')", + ): + pass + with e_header_right.tag( + "div", + classes=["link"], + title="Highlight this item", + onclick=f"makeElementVisible(event, '{id}', '{shadow_root_id}')", + ): + pass + with e_element_header.tag("div", classes=["element-header-toggle"], title="Toggle visibility"): + pass + + with result.tag( + "div", classes=["children", "populated"], styles={"display": "none" if status not in ["FAIL"] else "block"} + ) as e_children: + with e_children.tag("table", classes=["metadata", "keyword-metadata"]) as e_body: + if doc: + with e_body.tag("tr") as tr: + with tr.tag("th", text="Documentation:"): + pass + with tr.tag("td", classes=["doc"]) as td: + td.add_text(doc) + if tags: + with e_body.tag("tr") as tr: + with tr.tag("th", text="Tags:"): + pass + with tr.tag("td", classes=["tags"]) as td: + td.add_text(", ".join(tags)) + if timeout: + with e_body.tag("tr") as tr: + with tr.tag("th", text="Timeout:"): + pass + with tr.tag("td", classes=["timeout"]) as td: + td.add_text(timeout) + if source_name: + with e_body.tag("tr") as tr: + with tr.tag("th", text="Source:"): + pass + with tr.tag("td", classes=["source"]) as td: + td.add_text(source_name) + with e_body.tag("tr") as tr: + with tr.tag("th", text="Start / End / Elapsed:"): + pass + with tr.tag("td", classes=["message"]) as td: + td.add_text(str(start_time) + " / " + str(end_time) + " / " + elapsed_time_str) + if message: + with e_body.tag("tr") as tr: + with tr.tag("th", text="Message:"): + pass + with tr.tag("td", classes=["message"]) as td: + td.add_text(message) + + return result + + +def create_message_html( + id: str, + message: str, + level: str, + html: Union[str, bool] = False, + timestamp: Union[datetime, str, None] = None, + shadow_root_id: Optional[str] = None, +) -> Element: + result = Element("table", classes=["messages", f"{level.lower()}-message"], id=id) + + with result.tag("tr", classes=["message-row"]) as tr: + with tr.tag("td", classes=["time"]) as td: + if isinstance(timestamp, datetime): + td.add_text(timestamp.strftime("%H:%M:%S")) + else: + td.add_text(timestamp) + with tr.tag("td", classes=["level", level.lower()]) as td: + with td.tag("span", classes=["label", level.lower()]) as sp: + sp.add_text(level.upper()) + with tr.tag("td", classes=["message"]) as td: + if is_true(html): + td.add_raw(message) + else: + td.add_text(message) + with tr.tag( + "td", + classes=["select-message"], + onclick=f"selectMessage('{id}', '{shadow_root_id}')", + title="Select message text", + ) as td: + with td.tag("div"): + pass + + return result + + +if __name__ == "__main__": + # div = Element("div", id="main", classes=["test", "test2"], styles={"color": "red", "font-size": "12px"}) + # p = div.add_element(Element("p", text="Hello, world!")) + # p.add_element(Element("span", text="This is a test")) + # print(div) + + # body = Element("body") + # with body.tag("div", id="main", classes=["test", "test2"], styles={"color": "red"}) as div: + # with div.tag("p") as p: + # p.add_text("Hello, world!") + # with p.tag("span") as span: + # span.add_text("This is a test") + # with span.tag("br"): + # pass + # span.add_text("This is a test") + # with span.tag("br", id="test"): + # pass + # print(body) + + # r = create_keyword_html( + # id="ts-1-2-3-4-5-6", + # name="Test Keyword", + # owner="Test Library", + # doc="This is a test keyword", + # args=("arg1", "arg2"), + # assign=("${var1}", "${var2}"), + # tags=("tag1", "tag2"), + # timeout="10s", + # type="KEYWORD", + # status="PASS", + # message="This is a test message", + # start_time=datetime.now(timezone.utc), + # end_time=datetime.now(timezone.utc), + # elapsed_time=timedelta(seconds=5), + # ) + r = create_message_html("ts-1-2-3-4-5-6", "This is a test message", "INFO", timestamp="2021-10-10 12:00:00") + print(r) diff --git a/packages/repl_server/src/robotcode/repl_server/interpreter.py b/packages/repl_server/src/robotcode/repl_server/interpreter.py new file mode 100644 index 00000000..26fe9231 --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/interpreter.py @@ -0,0 +1,366 @@ +from dataclasses import dataclass, field +from datetime import datetime +from pathlib import Path +from threading import Event +from typing import TYPE_CHECKING, Iterator, List, Optional, Protocol, Union, runtime_checkable +from uuid import uuid4 + +from robot.running import Keyword + +from robotcode.core.utils.dataclasses import as_json +from robotcode.repl.base_interpreter import BaseInterpreter, is_true + +from .html_writer import Element, create_keyword_html, create_message_html + +if TYPE_CHECKING: + from robot import result, running + + +@dataclass +class ExecutionOutput: + mime: str + data: str + + +@dataclass +class ExecutionResult: + success: Optional[bool] = None + items: Optional[List[ExecutionOutput]] = None + + +class CellInputError(Exception): + pass + + +@dataclass +class ResultData: + pass + + +@dataclass +class MessageData(ResultData): + id: str + message: str + level: str + html: bool + timestamp: Optional[str] = None + + node_type: str = "message" + + +@dataclass +class RootResultData(ResultData): + items: List[ResultData] = field(default_factory=list) + + node_type: str = "root" + + +@runtime_checkable +class ResultDataWithChildren(Protocol): + items: List[ResultData] + + +@dataclass +class KeywordResultData(ResultData): + id: str + name: str + owner: str + source_name: str + doc: str + args: List[str] + assign: List[str] + tags: List[str] + timeout: Optional[str] + type: str + status: str + message: str + start_time: Optional[str] + end_time: Optional[str] + elapsed_time: Optional[float] + + items: List[ResultData] = field(default_factory=list) + + node_type: str = "keyword" + + +class Interpreter(BaseInterpreter): + def __init__( + self, + files: Optional[List[Path]] = None, + ) -> None: + super().__init__() + self.files = files + self.has_input = Event() + self.executed = Event() + self._code: List[str] = [] + self._html_result: Optional[Element] = None + self._result_stack: List[Element] = [] + self._output_stack: List[Element] = [] + self._shadow_marker: Optional[str] = None + self._success: Optional[bool] = None + self._result_data: Optional[ResultData] = None + self._result_data_stack: List[ResultData] = [] + self.collect_messages: bool = False + self._has_shutdown = False + + def shutdown(self) -> None: + self._code = [] + self._has_shutdown = True + self.has_input.set() + # self.executed.set() + + def execute(self, source: str) -> ExecutionResult: + self._result_stack = [] + self._result_data_stack = [] + + self._success = None + try: + self._shadow_marker = str(uuid4()) + + html_result = Element("div", classes=["robot-results"]) + + with html_result.tag( + "div", attributes={"data-shadow-marker": self._shadow_marker}, styles={"display": "none"} + ): + pass + + outer_test: Optional[Element] = None + with html_result.tag("div", classes=["result_body"]) as body: + with body.tag("div", classes=["test"]) as test: + with test.tag("div", classes=["children"], styles={"display": "block"}): + pass + outer_test = test + + self._html_result = outer_test + self._result_data = RootResultData() + + self.executed.clear() + + self._code.append(source) + self.has_input.set() + + self.executed.wait() + + return ExecutionResult( + self._success, + ( + [ + ExecutionOutput( + "x-application/robotframework-repl-log", as_json(self._result_data, compact=True) + ), + ExecutionOutput( + "x-application/robotframework-repl-html", html_result.as_str(only_children=True) + ), + ] + if self._success is not None + else [] + ), + ) + except BaseException as e: + return ExecutionResult(False, [ExecutionOutput("application/vnd.code.notebook.stderr", str(e))]) + + def get_input(self) -> Iterator[Optional[Keyword]]: + while self._code: + s = self._code.pop(0) + test, errors = self.get_test_body_from_string(s) + if errors: + raise CellInputError(errors) + + for kw in test.body: + yield kw + + def log_message( + self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None + ) -> None: + if self._result_data is not None and isinstance(self._result_data, ResultDataWithChildren): + self._result_data.items.append( + MessageData( + id=f"message-{len(self._result_data.items)}", + message=message, + level=level, + html=is_true(html), + timestamp=timestamp.strftime("%H:%M:%S") if isinstance(timestamp, datetime) else str(timestamp), + ) + ) + + if level in ("DEBUG", "TRACE"): + return + + if self._html_result is None: + return + + items = next( + ( + i + for i in self._html_result.children + if isinstance(i, Element) and i.tag_name == "div" and i.classes is not None and "children" in i.classes + ), + None, + ) + if items is None: + items = Element("div", classes=["children"]) + self._html_result.add_element(items) + + id = f"message-{len(items.children)}" + + message_data = create_message_html(id, message, level, html, timestamp, shadow_root_id=self._shadow_marker) + items.add_element(message_data) + + def message( + self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None + ) -> None: + if not self.collect_messages: + return + + if self._result_data is not None and isinstance(self._result_data, ResultDataWithChildren): + self._result_data.items.append( + MessageData( + id=f"message-{len(self._result_data.items)}", + message=message, + level=level, + html=is_true(html), + timestamp=timestamp.strftime("%H:%M:%S") if isinstance(timestamp, datetime) else str(timestamp), + ) + ) + + def start_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: + if data.type in ["IF/ELSE ROOT", "TRY/EXCEPT ROOT"]: + return + if self._result_data is not None: + kw_data = KeywordResultData( + id=result.id, + name=result.name if getattr(result, "name", None) else "", + owner=result.owner if getattr(result, "owner", None) else "", + source_name=result.source_name if getattr(result, "source_name", None) else "", + doc=result.doc if getattr(result, "doc", None) else "", + args=list(result.args) if getattr(result, "args", None) else [], + assign=list(result.assign) if getattr(result, "assign", None) else [], + tags=list(result.tags) if getattr(result, "tags", None) else [], + timeout=result.timeout if getattr(result, "timeout", None) else None, + type=result.type, + status=result.status, + message=result.message, + start_time=result.starttime, + end_time=result.endtime, + elapsed_time=result.elapsedtime, + ) + if self._result_data is not None and isinstance(self._result_data, ResultDataWithChildren): + self._result_data.items.append(kw_data) + self._result_data_stack.append(self._result_data) + self._result_data = kw_data + + if self._html_result is not None: + self._result_stack.append(self._html_result) + kw = self.create_keyword_html_element(result) + + children = next( + ( + i + for i in self._html_result.children + if isinstance(i, Element) + and i.tag_name == "div" + and i.classes is not None + and "children" in i.classes + ), + None, + ) + + if children is None: + self._html_result.add_element(kw) + else: + children.add_element(kw) + + self._html_result = kw + + def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None: + if data.type in ["IF/ELSE ROOT", "TRY/EXCEPT ROOT"]: + return + if self._result_data is not None: + if isinstance(self._result_data, KeywordResultData): + self._result_data.end_time = result.endtime + self._result_data.elapsed_time = result.elapsedtime + self._result_data.status = result.status + self._result_data.message = result.message + + self._result_data = self._result_data_stack.pop() + + if result.status == "FAIL": + self._success = False + elif result.status == "PASS" and self.last_result is not False: + self._success = True + + if self._html_result is not None and isinstance(self._html_result, Element): + + kw = self.create_keyword_html_element(result) + + old_children = next( + ( + i + for i in self._html_result.children + if isinstance(i, Element) + and i.tag_name == "div" + and i.classes is not None + and "children" in i.classes + ), + None, + ) + if old_children is not None: + new_children = next( + ( + i + for i in kw.children + if isinstance(i, Element) + and i.tag_name == "div" + and i.classes is not None + and "children" in i.classes + ), + None, + ) + if new_children is None: + new_children = Element("div", classes=["children"]) + self._html_result.add_element(new_children) + + for old_child in old_children.children: + if not ( + isinstance(old_child, Element) + and old_child.tag_name == "table" + and old_child.classes is not None + and "metadata" in old_child.classes + ): + new_children.add_element(old_child) + + self._html_result.children = kw.children + + self._html_result = self._result_stack.pop() + + def create_keyword_html_element(self, result: "result.Keyword") -> Element: + return create_keyword_html( + id=result.id, + name=result.name if getattr(result, "name", None) else None, + owner=result.owner if getattr(result, "owner", None) else None, + source_name=result.source_name if getattr(result, "source_name", None) else None, + doc=result.doc if getattr(result, "doc", None) else None, + args=result.args if getattr(result, "args", None) else (), + assign=result.assign if getattr(result, "assign", None) else (), + tags=result.tags if getattr(result, "tags", None) else (), + timeout=result.timeout if getattr(result, "timeout", None) else None, + type=result.type, + status=result.status, + message=result.message, + start_time=result.starttime, + end_time=result.endtime, + elapsed_time=result.elapsedtime, + shadow_root_id=self._shadow_marker, + ) + + def run_input(self) -> None: + self.has_input.wait() + if self._has_shutdown: + self.executed.set() + raise EOFError + + try: + return super().run_input() + finally: + self.has_input.clear() + self.executed.set() diff --git a/packages/repl_server/src/robotcode/repl_server/protocol.py b/packages/repl_server/src/robotcode/repl_server/protocol.py new file mode 100644 index 00000000..f3e817f6 --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/protocol.py @@ -0,0 +1,32 @@ +import sys +from typing import Optional + +from robotcode.jsonrpc2.protocol import JsonRPCProtocol, rpc_method + +from .interpreter import ExecutionResult, Interpreter + + +class ReplServerProtocol(JsonRPCProtocol): + def __init__(self, interpreter: Interpreter): + super().__init__() + self.interpreter = interpreter + self._is_shutdown = False + + @rpc_method(name="initialize", threaded=True) + def initialize(self, message: str) -> str: + return "yeah initialized " + message + + @rpc_method(name="executeCell", threaded=True) + def execute_cell(self, source: str) -> Optional[ExecutionResult]: + return self.interpreter.execute(source) + + @rpc_method(name="shutdown", threaded=True) + def shutdown(self) -> None: + try: + self.interpreter.shutdown() + finally: + self._is_shutdown = True + + @rpc_method(name="exit", threaded=True) + def exit(self) -> None: + sys.exit(0 if self._is_shutdown else 1) diff --git a/packages/repl_server/src/robotcode/repl_server/py.typed b/packages/repl_server/src/robotcode/repl_server/py.typed new file mode 100644 index 00000000..1242d432 --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561. diff --git a/packages/repl_server/src/robotcode/repl_server/server.py b/packages/repl_server/src/robotcode/repl_server/server.py new file mode 100644 index 00000000..7e72e72b --- /dev/null +++ b/packages/repl_server/src/robotcode/repl_server/server.py @@ -0,0 +1,24 @@ +from typing import Optional + +from robotcode.core.types import ServerMode, TcpParams +from robotcode.jsonrpc2.server import JsonRPCServer + +from .interpreter import Interpreter +from .protocol import ReplServerProtocol + +TCP_DEFAULT_PORT = 6601 + + +class ReplServer(JsonRPCServer[ReplServerProtocol]): + def __init__( + self, + interpreter: Interpreter, + mode: ServerMode = ServerMode.STDIO, + tcp_params: TcpParams = TcpParams(None, TCP_DEFAULT_PORT), + pipe_name: Optional[str] = None, + ): + super().__init__(mode=mode, tcp_params=tcp_params, pipe_name=pipe_name) + self.interpreter = interpreter + + def create_protocol(self) -> ReplServerProtocol: + return ReplServerProtocol(self.interpreter) diff --git a/pyproject.toml b/pyproject.toml index 1413fcbe..3f3a585e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,7 @@ lint = ["robotframework-robocop>=2.0.0"] tidy = ["robotframework-tidy>=2.0.0"] rest = ["docutils"] repl = ["robotcode-repl==0.99.0"] +replserver = ["robotcode-repl-server==0.99.0"] colored = ["rich"] all = [ "robotcode-debugger==0.99.0", @@ -87,6 +88,7 @@ all = [ "robotcode-runner==0.99.0", "robotcode-analyze==0.99.0", "robotcode-repl==0.99.0", + "robotcode-repl-server==0.99.0", "PyYAML>=5.4", "robotframework-robocop>=2.0.0", "robotframework-tidy>=2.0.0", @@ -173,7 +175,7 @@ target-version = "py38" extend-exclude = ["bundled/libs", ".hatch"] [tool.ruff.lint] -ignore = ["E741", "N805", "N999", "RUF012", "RUF006", "ISC001"] +ignore = ["E741", "N805", "N999", "RUF012", "RUF006", "ISC001", "RUF021", "RUF022"] select = [ "E", "F", diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index e251fd1c..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "paths": { - "*": [ - "types/*" - ] - }, - "module": "NodeNext", - "moduleResolution": "NodeNext", - "target": "ES2022", - "outDir": "out", - "lib": [ - "es6", - "dom", - "ES2018", - "ES2019", - "ES2020", - "ES2021", - "ES2022", - ], - "sourceMap": true, - "rootDir": "vscode-client", - "strict": true, - // "experimentalDecorators": true, - // "emitDecoratorMetadata": true, - // "esModuleInterop": true, - // "allowSyntheticDefaultImports": true, - "noImplicitAny": true, - "noImplicitThis": true, - "noUnusedLocals": true, - //"noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "resolveJsonModule": true, - "removeComments": true, - "noImplicitReturns": true - }, - "exclude": [ - "node_modules", - ".vscode-test", - "out", - "htmlcov" - ] -} \ No newline at end of file diff --git a/types/vscode.proposed.notebookReplDocument.d.ts b/types/vscode.proposed.notebookReplDocument.d.ts deleted file mode 100644 index 88c9a772..00000000 --- a/types/vscode.proposed.notebookReplDocument.d.ts +++ /dev/null @@ -1,35 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module "vscode" { - export interface NotebookDocumentShowOptions { - /** - * The notebook should be opened in a REPL editor, - * where the last cell of the notebook is an input box and the other cells are the read-only history. - * When the value is a string, it will be used as the label for the editor tab. - */ - readonly asRepl?: - | boolean - | string - | { - /** - * The label to be used for the editor tab. - */ - readonly label: string; - }; - } - - export interface NotebookEditor { - /** - * Information about the REPL editor if the notebook was opened as a repl. - */ - replOptions?: { - /** - * The index where new cells should be appended. - */ - appendIndex: number; - }; - } -} diff --git a/vscode-client/config.ts b/vscode-client/extension/config.ts similarity index 100% rename from vscode-client/config.ts rename to vscode-client/extension/config.ts diff --git a/vscode-client/debugmanager.ts b/vscode-client/extension/debugmanager.ts similarity index 100% rename from vscode-client/debugmanager.ts rename to vscode-client/extension/debugmanager.ts diff --git a/vscode-client/extension.ts b/vscode-client/extension/index.ts similarity index 100% rename from vscode-client/extension.ts rename to vscode-client/extension/index.ts diff --git a/vscode-client/keywordsTreeViewProvider.ts b/vscode-client/extension/keywordsTreeViewProvider.ts similarity index 100% rename from vscode-client/keywordsTreeViewProvider.ts rename to vscode-client/extension/keywordsTreeViewProvider.ts diff --git a/vscode-client/languageToolsManager.ts b/vscode-client/extension/languageToolsManager.ts similarity index 100% rename from vscode-client/languageToolsManager.ts rename to vscode-client/extension/languageToolsManager.ts diff --git a/vscode-client/languageclientsmanger.ts b/vscode-client/extension/languageclientsmanger.ts similarity index 100% rename from vscode-client/languageclientsmanger.ts rename to vscode-client/extension/languageclientsmanger.ts diff --git a/vscode-client/net_utils.ts b/vscode-client/extension/net_utils.ts similarity index 100% rename from vscode-client/net_utils.ts rename to vscode-client/extension/net_utils.ts diff --git a/vscode-client/extension/notebook.ts b/vscode-client/extension/notebook.ts new file mode 100644 index 00000000..f21b7ffa --- /dev/null +++ b/vscode-client/extension/notebook.ts @@ -0,0 +1,437 @@ +/* eslint-disable class-methods-use-this */ +import { TextDecoder, TextEncoder } from "util"; +import * as vscode from "vscode"; +import { LanguageClientsManager } from "./languageclientsmanger"; +import { PythonManager } from "./pythonmanger"; +import * as cp from "child_process"; +import * as rpc from "vscode-jsonrpc/node"; +import { withTimeout } from "./utils"; + +interface RawNotebook { + cells: RawNotebookCell[]; +} + +interface RawNotebookCellOutputItem { + mime: string; + data: number[]; +} + +interface RawNotebookCellOutput { + items: RawNotebookCellOutputItem[]; + metadata?: { [key: string]: unknown }; +} + +interface RawNotebookCellExecutionSummary { + executionOrder?: number; + success?: boolean; + timing?: { + startTime: number; + endTime: number; + }; +} + +interface RawNotebookCell { + source: string[]; + languageId?: string; + cell_type: "code" | "markdown"; + outputs?: RawNotebookCellOutput[]; + executionSummary?: RawNotebookCellExecutionSummary; +} + +interface ExecutionOutput { + mime: string; + data: string; +} + +interface ExecutionResult { + success?: boolean; + items?: ExecutionOutput[]; + metadata?: { [key: string]: unknown }; +} + +export class REPLNotebookSerializer implements vscode.NotebookSerializer { + async deserializeNotebook(content: Uint8Array, _token: vscode.CancellationToken): Promise { + const contents = new TextDecoder().decode(content); + + let raw: RawNotebookCell[]; + try { + raw = (JSON.parse(contents)).cells; + } catch { + raw = []; + } + + const cells = raw.map((item) => { + const result = new vscode.NotebookCellData( + item.cell_type === "code" ? vscode.NotebookCellKind.Code : vscode.NotebookCellKind.Markup, + item.source.join("\n"), + item.languageId ?? (item.cell_type === "code" ? "robotframework-repl" : "markdown"), + ); + result.outputs = item.outputs?.map((item) => { + return new vscode.NotebookCellOutput( + item.items.map((item) => { + return { + mime: item.mime, + data: new Uint8Array(item.data), + }; + }), + item.metadata, + ); + }); + + result.executionSummary = item.executionSummary + ? { + executionOrder: item.executionSummary.executionOrder, + success: item.executionSummary.success, + timing: item.executionSummary.timing + ? { + startTime: item.executionSummary.timing.startTime, + endTime: item.executionSummary.timing.endTime, + } + : undefined, + } + : undefined; + + return result; + }); + + return new vscode.NotebookData(cells); + } + + async serializeNotebook(data: vscode.NotebookData, _token: vscode.CancellationToken): Promise { + const contents: RawNotebookCell[] = []; + + for (const cell of data.cells) { + contents.push({ + cell_type: cell.kind === vscode.NotebookCellKind.Code ? "code" : "markdown", + languageId: cell.languageId, + source: cell.value.split(/\r?\n/g), + outputs: cell.outputs?.map((item) => { + return { + metadata: item.metadata ? { ...item.metadata } : undefined, + items: item.items.map((item) => { + return { + mime: item.mime, + data: Array.from(item.data), + }; + }), + }; + }), + executionSummary: cell.executionSummary + ? { + executionOrder: cell.executionSummary.executionOrder, + success: cell.executionSummary.success, + timing: cell.executionSummary.timing ? { ...cell.executionSummary.timing } : undefined, + } + : undefined, + }); + } + + return new TextEncoder().encode(JSON.stringify({ cells: contents })); + } +} + +export class ReplServerClient { + private exitNotification = new rpc.NotificationType("testNotification"); + + constructor( + public document: vscode.NotebookDocument, + public readonly extensionContext: vscode.ExtensionContext, + public readonly pythonManager: PythonManager, + readonly _outputChannel: vscode.OutputChannel, + ) { + this._outputChannel.appendLine("Starting REPL server..."); + } + + connection: rpc.MessageConnection | undefined; + childProcess: cp.ChildProcessWithoutNullStreams | undefined; + private _cancelationTokenSource: vscode.CancellationTokenSource | undefined; + + dispose(): void { + this.exitClient().finally(() => {}); + } + + async sendShutdown(): Promise { + await this.connection?.sendRequest("shutdown"); + } + + async _waitForServerToExit(): Promise { + while (this.childProcess?.exitCode === null) { + await new Promise((resolve) => setTimeout(resolve, 100)); + } + } + + async exitClient(): Promise { + this.cancelCurrentExecution(); + + try { + await withTimeout(this.sendShutdown(), 50000); + } catch (e) { + this._outputChannel.appendLine(`Error shutting down server: ${e?.toString()}`); + } + this.connection?.sendNotification(this.exitNotification); + + try { + await withTimeout(this._waitForServerToExit(), 5000); + } catch (e) { + this._outputChannel.appendLine(`Error waiting for server to exit: ${e?.toString()}`); + + this.connection?.dispose(); + this.childProcess?.kill(); + } + } + + cancelCurrentExecution(): void { + if (this._cancelationTokenSource) { + this._cancelationTokenSource.cancel(); + this._cancelationTokenSource.dispose(); + } + } + + async ensureInitialized(): Promise { + if (this.connection) { + return; + } + + let folder = vscode.workspace.getWorkspaceFolder(this.document.uri); + if (!folder) { + if (vscode.workspace.workspaceFolders?.length == 1) { + folder = vscode.workspace.workspaceFolders[0]; + } else { + // TODO: select a workspace folder if there are multiple and ensure that robotframework is installed. + throw new Error("No workspace folder found for the document."); + } + } + + const pipeName = rpc.generateRandomPipeName(); + + const transport = await rpc.createClientPipeTransport(pipeName, "utf-8"); + + const { pythonCommand, final_args } = await this.pythonManager.buildRobotCodeCommand( + folder, + //["-v", "--debugpy", "--debugpy-wait-for-client", "repl-server", "--pipe", pipeName], + ["repl-server", "--pipe", pipeName, "--source", this.document.uri.fsPath], + undefined, + true, + true, + ); + + this._outputChannel.appendLine(`Starting server with command: ${pythonCommand} ${final_args.join(" ")}`); + + this.childProcess = cp.spawn(pythonCommand, final_args, { cwd: folder.uri.fsPath }); + + this.childProcess.stdout.on("data", (message) => { + this._outputChannel.appendLine(`${message}`); + }); + + this.childProcess.stderr.on("data", (message) => { + this._outputChannel.appendLine(`${message}`); + }); + + this.childProcess.on("exit", (code) => { + this.cancelCurrentExecution(); + + this._outputChannel.appendLine(`Server exited with code ${code}`); + if (this.connection) { + this._outputChannel.appendLine("Disposing connection..."); + this.connection.dispose(); + this.connection = undefined; + } + }); + this.childProcess.on("error", (error) => { + this._outputChannel.appendLine(`Error starting server: ${error?.toString()}`); + }); + + let connection: rpc.MessageConnection | undefined = undefined; + + try { + this._outputChannel.appendLine("Waiting for server to connect..."); + const [reader, writer] = await withTimeout(transport.onConnected(), 5000); + this._outputChannel.appendLine("Server connected."); + + connection = rpc.createMessageConnection(reader, writer); + + connection.listen(); + + const result = await connection.sendRequest("initialize", { message: "Hello World" }); + this._outputChannel.appendLine(`Server initialized: ${result}`); + } catch (error) { + this._outputChannel.appendLine(`Error connecting to server: ${error?.toString()}`); + throw new Error("Error connecting to RPC server", { cause: error }); + } + + this.connection = connection; + } + + async executeCell(source: string): Promise<{ success?: boolean; output: vscode.NotebookCellOutput }> { + this._cancelationTokenSource = new vscode.CancellationTokenSource(); + + try { + await this.ensureInitialized(); + + const result = await this.connection?.sendRequest( + "executeCell", + { source }, + this._cancelationTokenSource.token, + ); + + return { + success: result?.success, + output: new vscode.NotebookCellOutput( + result?.items?.flatMap((item) => { + return item.mime === "x-application/robotframework-repl-log" + ? [ + vscode.NotebookCellOutputItem.json(JSON.parse(item.data), item.mime), + vscode.NotebookCellOutputItem.json(JSON.parse(item.data), "text/x-json"), + ] + : [vscode.NotebookCellOutputItem.text(item.data, item.mime)]; + }) ?? [], + result?.metadata, + ), + }; + } finally { + this._cancelationTokenSource.dispose(); + this._cancelationTokenSource = undefined; + } + } +} + +export class REPLNotebookController { + readonly controllerId = "robotframework-repl"; + readonly notebookType = "robotframework-repl"; + readonly label = "Robot Framework REPL"; + readonly supportedLanguages = ["robotframework-repl", "robotframework"]; + readonly description = "A Robot Framework REPL notebook controller"; + readonly supportsExecutionOrder = true; + readonly controller: vscode.NotebookController; + readonly _clients = new Map(); + + _outputChannel: vscode.OutputChannel | undefined; + + private readonly _disposables: vscode.Disposable; + private _executionOrder = 0; + private readonly finalizeRegistry: FinalizationRegistry<{ dispose(): unknown }>; + + constructor( + public readonly extensionContext: vscode.ExtensionContext, + public readonly pythonManager: PythonManager, + ) { + this.controller = vscode.notebooks.createNotebookController(this.controllerId, this.notebookType, this.label); + this.finalizeRegistry = new FinalizationRegistry((heldValue) => { + heldValue.dispose(); + }); + + this.controller.supportedLanguages = this.supportedLanguages; + this.controller.supportsExecutionOrder = true; + this.controller.executeHandler = this._execute.bind(this); + this.controller.supportsExecutionOrder = true; + this.controller.description = "Robot Framework REPL"; + this.controller.interruptHandler = async (notebook: vscode.NotebookDocument) => { + this._clients.get(notebook)?.dispose(); + this._clients.delete(notebook); + }; + this._disposables = vscode.Disposable.from( + this.controller, + vscode.workspace.onDidCloseNotebookDocument((document) => { + this._clients.get(document)?.dispose(); + this._clients.delete(document); + }), + ); + } + + outputChannel(): vscode.OutputChannel { + if (!this._outputChannel) { + this._outputChannel = vscode.window.createOutputChannel("RobotCode REPL"); + } + return this._outputChannel; + } + + dispose(): void { + for (const client of this._clients.values()) { + client.dispose(); + } + this._disposables.dispose(); + } + + private getClient(document: vscode.NotebookDocument): ReplServerClient { + let client = this._clients.get(document); + if (!client) { + client = new ReplServerClient(document, this.extensionContext, this.pythonManager, this.outputChannel()); + this.finalizeRegistry.register(document, client); + this._clients.set(document, client); + } + return client; + } + + private async _execute( + cells: vscode.NotebookCell[], + _notebook: vscode.NotebookDocument, + _controller: vscode.NotebookController, + ): Promise { + const client = this.getClient(_notebook); + + for (const cell of cells) { + await this._doExecution(client, cell); + } + } + + private async _doExecution(client: ReplServerClient, cell: vscode.NotebookCell): Promise { + const execution = this.controller.createNotebookCellExecution(cell); + execution.executionOrder = ++this._executionOrder; + let success: boolean | undefined = undefined; + + execution.start(Date.now()); + try { + const source = cell.document.getText(); + const result = await client.executeCell(source); + if (result !== undefined) { + success = result.success; + + await execution.clearOutput(); + await execution.appendOutput(result.output); + } + } catch (error) { + await execution.clearOutput(); + await execution.appendOutput([ + new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.error( + error instanceof Error ? error : new Error(error?.toString() ?? "Unknown error"), + ), + ]), + ]); + } finally { + execution.end(success, Date.now()); + } + } +} + +export class NotebookManager { + private readonly _disposables: vscode.Disposable; + private _notebookController: REPLNotebookController; + + constructor( + public readonly extensionContext: vscode.ExtensionContext, + public readonly pythonManager: PythonManager, + public readonly languageClientsManager: LanguageClientsManager, + public readonly outputChannel: vscode.OutputChannel, + ) { + this._notebookController = new REPLNotebookController(extensionContext, pythonManager); + + this._disposables = vscode.Disposable.from( + this._notebookController, + vscode.workspace.registerNotebookSerializer("robotframework-repl", new REPLNotebookSerializer()), + vscode.commands.registerCommand("robotcode.createNewNotebook", async () => { + const newNotebook = await vscode.workspace.openNotebookDocument( + this._notebookController.notebookType, + new vscode.NotebookData([ + new vscode.NotebookCellData(vscode.NotebookCellKind.Code, "Log Hello World!!!", "robotframework-repl"), + ]), + ); + await vscode.commands.executeCommand("vscode.openWith", newNotebook.uri, "robotframework-repl"); + }), + ); + } + + dispose(): void { + this._disposables.dispose(); + } +} diff --git a/vscode-client/pythonmanger.ts b/vscode-client/extension/pythonmanger.ts similarity index 100% rename from vscode-client/pythonmanger.ts rename to vscode-client/extension/pythonmanger.ts diff --git a/vscode-client/testcontrollermanager.ts b/vscode-client/extension/testcontrollermanager.ts similarity index 100% rename from vscode-client/testcontrollermanager.ts rename to vscode-client/extension/testcontrollermanager.ts diff --git a/vscode-client/extension/tsconfig.json b/vscode-client/extension/tsconfig.json new file mode 100644 index 00000000..17927e2e --- /dev/null +++ b/vscode-client/extension/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "ES2022", + "lib": [ + "ES7", + "DOM", + "ES2018", + "ES2019", + "ES2020", + "ES2021", + "ES2022", + ], + "outDir": "../../out/extension", + "rootDir": "." + }, + "exclude": [ + "../../node_modules", + ".vscode-test", + ] +} \ No newline at end of file diff --git a/vscode-client/utils.ts b/vscode-client/extension/utils.ts similarity index 95% rename from vscode-client/utils.ts rename to vscode-client/extension/utils.ts index b4768736..c063b2b6 100644 --- a/vscode-client/utils.ts +++ b/vscode-client/extension/utils.ts @@ -224,3 +224,8 @@ export function truncateAndReplaceNewlines(str: string, maxLength: number = 50): } return processedString; } + +export function withTimeout(promise: Thenable, ms: number): Promise { + const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout exceeded")), ms)); + return Promise.race([promise, timeout]); +} diff --git a/vscode-client/notebook.ts b/vscode-client/notebook.ts deleted file mode 100644 index 8c838af0..00000000 --- a/vscode-client/notebook.ts +++ /dev/null @@ -1,126 +0,0 @@ -/* eslint-disable class-methods-use-this */ -import { TextDecoder, TextEncoder } from "util"; -import * as vscode from "vscode"; -import { LanguageClientsManager } from "./languageclientsmanger"; -import { PythonManager } from "./pythonmanger"; - -interface RawNotebook { - cells: RawNotebookCell[]; -} - -interface RawNotebookCell { - source: string[]; - cell_type: "code" | "markdown"; -} - -export class REPLNotebookSerializer implements vscode.NotebookSerializer { - async deserializeNotebook(content: Uint8Array, _token: vscode.CancellationToken): Promise { - const contents = new TextDecoder().decode(content); - - let raw: RawNotebookCell[]; - try { - raw = (JSON.parse(contents)).cells; - } catch { - raw = []; - } - - const cells = raw.map( - (item) => - new vscode.NotebookCellData( - item.cell_type === "code" ? vscode.NotebookCellKind.Code : vscode.NotebookCellKind.Markup, - item.source.join("\n"), - item.cell_type === "code" ? "robotframework-repl" : "markdown", - ), - ); - - return new vscode.NotebookData(cells); - } - - async serializeNotebook(data: vscode.NotebookData, _token: vscode.CancellationToken): Promise { - const contents: RawNotebookCell[] = []; - - for (const cell of data.cells) { - contents.push({ - cell_type: cell.kind === vscode.NotebookCellKind.Code ? "code" : "markdown", - source: cell.value.split(/\r?\n/g), - }); - } - - return new TextEncoder().encode(JSON.stringify(contents)); - } -} - -export class REPLNotebookController { - readonly controllerId = "robotframework-repl"; - readonly notebookType = "robotframework-repl"; - readonly label = "Robot Framework REPL"; - readonly supportedLanguages = ["robotframework-repl", "robotframework"]; - - readonly controller: vscode.NotebookController; - - private _executionOrder = 0; - - constructor() { - this.controller = vscode.notebooks.createNotebookController(this.controllerId, this.notebookType, this.label); - - this.controller.supportedLanguages = this.supportedLanguages; - this.controller.supportsExecutionOrder = true; - this.controller.executeHandler = this._execute.bind(this); - this.controller.supportsExecutionOrder = true; - this.controller.description = "Robot Framework REPL"; - this.controller.interruptHandler = async () => { - // Do something here to interrupt execution. - }; - } - - dispose(): void { - this.controller.dispose(); - } - - private _execute( - cells: vscode.NotebookCell[], - _notebook: vscode.NotebookDocument, - _controller: vscode.NotebookController, - ): void { - for (const cell of cells) { - this._doExecution(cell); - } - } - - private async _doExecution(cell: vscode.NotebookCell): Promise { - const execution = this.controller.createNotebookCellExecution(cell); - execution.executionOrder = ++this._executionOrder; - execution.start(Date.now()); // Keep track of elapsed time to execute cell. - - /* Do some execution here; not implemented */ - - execution.replaceOutput([ - new vscode.NotebookCellOutput([vscode.NotebookCellOutputItem.text("Dummy output text!")]), - ]); - execution.end(true, Date.now()); - } -} - -export class NotebookManager { - private readonly _disposables: vscode.Disposable; - private _notebookController: REPLNotebookController; - - constructor( - public readonly extensionContext: vscode.ExtensionContext, - public readonly pythonManager: PythonManager, - public readonly languageClientsManager: LanguageClientsManager, - public readonly outputChannel: vscode.OutputChannel, - ) { - this._notebookController = new REPLNotebookController(); - this._disposables = vscode.Disposable.from( - this._notebookController, - vscode.workspace.registerNotebookSerializer("robotframework-repl", new REPLNotebookSerializer(), { - transientOutputs: true, - }), - ); - } - - dispose(): void { - this._disposables.dispose(); - } -} diff --git a/vscode-client/rendererHtml/css/common.csstemp b/vscode-client/rendererHtml/css/common.csstemp new file mode 100644 index 00000000..c7121a5d --- /dev/null +++ b/vscode-client/rendererHtml/css/common.csstemp @@ -0,0 +1,476 @@ +:host { + /* --text-color: black; + --background-color: white; + --primary-color: #ddd; + --secondary-color: #ccc; + --link-color: #15c; + --link-hover-color: #61c; + --highlight-color: #eee; */ + --target-color: #f9f9f9; + --pass-color: #97bd61; + --fail-color: #ce3e01; + --warn-color: #fed84f; + --pass-link-color: #098a09; + --warn-link-color: #927201; + --fail-link-color: #ce3e01; + --ascending-icon: url(data:image/gif;base64,R0lGODlhCwAJAKEAAAAAAH9/fwAAAAAAACH5BAEAAAIALAAAAAALAAkAAAIUlBWnFr3cnIr0WQOyBmvzp13CpxQAOw==); + --descending-icon: url(data:image/gif;base64,R0lGODlhCwAJAKEAAAAAAH9/fwAAAAAAACH5BAEAAAIALAAAAAALAAkAAAIUlAWnBr3cnIr0WROyDmvzp13CpxQAOw==); +} + +@media (prefers-color-scheme: dark) { + :host { + color-scheme: dark; + } +} + +[data-theme="dark"] { + /* --text-color: #e2e1d7; + --background-color: #1c2227; + --primary-color: #26373b; + --secondary-color: #424f5a; + --link-color: #8cc4ff; + --link-hover-color: #bb86fc; + --highlight-color: #002b36; */ + --target-color: #1a252e; + --pass-link-color: #97bd61; + --warn-link-color: #fed84f; + --fail-link-color: #ff9b8f; + --ascending-icon: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAJAgMAAACZCj6+AAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAlQTFRFAAAAfn5+////f/cqYgAAAAN0Uk5TAP//RFDWIQAAACdJREFUeJxjYHBgYGAMYGBgDWFgEA1lAAOtVQwMXCsYGJgWADkNDAA78QP9oKr7vwAAAABJRU5ErkJggg==); + --descending-icon: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAJAgMAAACZCj6+AAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAlQTFRFAAAA////fn5+K6jOaAAAAAN0Uk5TAP//RFDWIQAAACdJREFUeJxjYHBgYGAMYGBgDWFgEA1lAAOtVQwMXCsYGJgWADkNDAA78QP9oKr7vwAAAABJRU5ErkJggg==); +} + +/* Generic and misc styles */ +.result_body { + font-family: Helvetica, sans-serif; + /* font-size: 0.8em; */ + /* color: black; */ + /* Fallback value */ + /* color: var(--text-color); */ + /* padding: 3px; */ + /* background: white; */ + /* Fallback value */ + /* background: var(--background-color); */ + /* margin-left: 15px; */ +} + +.result_body[theme-toggled] { + transition: background 0.3s, background-color 0.3s, color 0.3s, border-color 0.3s; +} + +table { + table-layout: fixed; + word-wrap: break-word; + empty-cells: show; + font-size: 1em; +} + +th, +td { + vertical-align: top; +} + +br { + mso-data-placement: same-cell; + /* maintain line breaks in Excel */ +} + +hr { + background: #ccc; + /* Fallback value */ + background: var(--secondary-color); + height: 1px; + border: 0; +} + +a, +a:link, +a:visited { + text-decoration: none; + color: #15c; + /* Fallback value */ + color: var(--link-color); +} + +a>img { + border-width: 1px !important; + border-style: solid !important; + border-color: #15c !important; + /* Fallback value */ + border-color: var(--link-color) !important; +} + +a:hover, +a:active { + text-decoration: underline; + color: #61c; + /* Fallback value */ + color: var(--link-hover-color); +} + +select { + background-color: white; + /* Fallback value */ + background-color: var(--background-color); + color: black; + /* Fallback value */ + color: var(--text-color); + border-width: 2px; + border-style: solid; + border-color: #ccc; + /* Fallback value */ + border-color: var(--secondary-color); + border-radius: 4px; +} + +.parent-name { + font-size: 0.7em; + letter-spacing: -0.07em; +} + +.message { + white-space: pre-wrap; +} + +/* Headers */ +#header { + width: 65em; + height: 3em; + margin: 20px 0 6px 0; +} + +h1 { + float: left; + margin: 0 0 0.5em 0; + width: 75%; +} + +h2 { + clear: left; +} + +#generated { + float: right; + text-align: right; + font-size: 0.9em; + white-space: nowrap; +} + +/* Documentation headers */ +.doc>h2 { + font-size: 1.2em; +} + +.doc>h3 { + font-size: 1.1em; +} + +.doc>h4 { + font-size: 1.0em; +} + +/* Status text colors -- !important allows using them in links */ +.fail { + color: #ce3e01 !important; + /* Fallback value */ + color: var(--fail-link-color) !important; + font-weight: bold; +} + +.pass { + color: #098a09 !important; + /* Fallback value */ + color: var(--pass-link-color) !important; +} + +.skip { + color: #927201 !important; + /* Fallback value */ + color: var(--warn-link-color) !important; + font-weight: bold; +} + +.label { + padding: 2px 5px; + font-size: 0.75em; + letter-spacing: 1px; + white-space: nowrap; + color: black; + /* Fallback value */ + color: var(--text-color); + background-color: #ddd; + /* Fallback value */ + background-color: var(--primary-color); + border-radius: 3px; +} + +.label.debug, +.label.trace, +.label.error, +.label.keyword { + letter-spacing: 0; +} + +.label.pass, +.label.fail, +.label.error, +.label.skip, +.label.warn { + font-weight: bold; +} + +.label.pass { + background-color: #97bd61; + /* Fallback value */ + background-color: var(--pass-color); + color: #000 !important; +} + +.label.fail, +.label.error { + background-color: #ce3e01; + /* Fallback value */ + background-color: var(--fail-color); + color: #fff !important; +} + +.label.skip, +.label.warn { + background-color: #fed84f; + /* Fallback value */ + background-color: var(--warn-color); + color: #000 !important; +} + +/* Top right header */ +#top-right-header { + position: fixed; + top: 0; + right: 0; + z-index: 1000; + width: 12em; + text-align: center; +} + +#report-or-log-link a { + display: block; + background: black; + color: white; + text-decoration: none; + font-weight: bold; + letter-spacing: 0.1em; + padding: 0.3em 0; + border-bottom-left-radius: 4px; +} + +#report-or-log-link a:hover { + color: #ddd; +} + +#log-level-selector { + padding: 0.3em 0; + font-size: 0.9em; + border-bottom-left-radius: 4px; + background: #ddd; + /* Fallback value */ + background: var(--primary-color); +} + +/* Statistics table */ +.statistics { + width: 65em; + border-collapse: collapse; + empty-cells: show; + margin-bottom: 1em; +} + +.statistics tr:hover { + background: #eee; + /* Fallback value */ + background: var(--highlight-color); + cursor: pointer; +} + +.statistics th, +.statistics td { + border-width: 1px; + border-style: solid; + border-color: #ccc; + /* Fallback value */ + border-color: var(--secondary-color); + padding: 0.1em 0.3em; +} + +.statistics th { + background-color: #ddd; + /* Fallback value */ + background-color: var(--primary-color); + padding: 0.2em 0.3em; +} + +.statistics td { + vertical-align: middle; +} + +.stats-col-stat { + width: 4.5em; + text-align: center; +} + +.stats-col-elapsed { + width: 5.5em; + text-align: center; +} + +.stats-col-graph { + width: 9em; +} + +th.stats-col-graph:hover { + cursor: default; +} + +.stat-name { + float: left; +} + +.stat-name a, +.stat-name span { + font-weight: bold; +} + +.tag-links { + font-size: 0.9em; + float: right; + margin-top: 0.05em; +} + +.tag-links span { + margin-left: 0.2em; +} + +/* Statistics graph */ +.graph, +.empty-graph { + border-width: 1px; + border-style: solid; + border-color: #ccc; + /* Fallback value */ + border-color: var(--secondary-color); + width: auto; + height: 7px; + padding: 0; +} + +.empty-graph { + background: #eee; + /* Fallback value */ + background: var(--highlight-color); +} + +.pass-bar, +.fail-bar, +.skip-bar { + float: left; + height: 100%; +} + +.fail-bar { + background: #ce3e01; + /* Fallback value */ + background: var(--fail-color); +} + +.pass-bar { + background: #97bd61; + /* Fallback value */ + background: var(--pass-color); +} + +.skip-bar { + background: #fed84f; + /* Fallback value */ + background: var(--warn-color); +} + +/* Tablesorter - adapted from provided Blue Skin */ +.tablesorter-header { + background-image: url(data:image/gif;base64,R0lGODlhCwAJAIAAAH9/fwAAACH5BAEAAAEALAAAAAALAAkAAAIRjAOnBr3cnIr0WUjTrC9e9BQAOw==); + background-repeat: no-repeat; + background-position: center right; + cursor: pointer; +} + +.tablesorter-header:hover { + background-color: #ccc; + /* Fallback value */ + background-color: var(--secondary-color); +} + +.tablesorter-headerAsc { + background-image: url(data:image/gif;base64,R0lGODlhCwAJAKEAAAAAAH9/fwAAAAAAACH5BAEAAAIALAAAAAALAAkAAAIUlBWnFr3cnIr0WQOyBmvzp13CpxQAOw==); + /* Fallback value */ + background-image: var(--ascending-icon); + background-color: #ccc !important; + /* Fallback value */ + background-color: var(--secondary-color) !important; +} + +.tablesorter-headerDesc { + background-image: url(data:image/gif;base64,R0lGODlhCwAJAKEAAAAAAH9/fwAAAAAAACH5BAEAAAIALAAAAAALAAkAAAIUlAWnBr3cnIr0WROyDmvzp13CpxQAOw==); + /* Fallback value */ + background-image: var(--descending-icon); + background-color: #ccc !important; + /* Fallback value */ + background-color: var(--secondary-color) !important; +} + +.sorter-false { + background-image: none; + cursor: default; +} + +.sorter-false:hover { + background-color: #ddd; + /* Fallback value */ + background-color: var(--primary-color); +} + +#theme-toggle { + position: fixed; + right: 0; + bottom: 0; + width: 28px; + height: 28px; + border: none; + padding: 4px; + z-index: 1000; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + background: var(--highlight-color); +} + +[data-theme="dark"] .dark-mode-icon, +[data-theme="light"] .light-mode-icon { + display: none; +} + +[data-theme="dark"] .light-mode-icon, +[data-theme="light"] .dark-mode-icon { + display: block; +} + +@keyframes highlight { + 0% { + background: var(--primary-color) + } + + 100% { + background: var(--target-color); + } +} + +:target { + background: var(--target-color); + transition: background 0.3s; + animation: highlight 4s; +} \ No newline at end of file diff --git a/vscode-client/rendererHtml/css/doc_formatting.csstemp b/vscode-client/rendererHtml/css/doc_formatting.csstemp new file mode 100644 index 00000000..9293b545 --- /dev/null +++ b/vscode-client/rendererHtml/css/doc_formatting.csstemp @@ -0,0 +1,77 @@ +.doc>* { + margin: 0.7em 1em 0.1em 1em; + padding: 0; +} + +.doc>p, +.doc>h1, +.doc>h2, +.doc>h3, +.doc>h4 { + margin: 0.7em 0 0.1em 0; +} + +.doc>*:first-child { + margin-top: 0.1em; +} + +.doc table { + background: transparent; + border-collapse: collapse; + empty-cells: show; + font-size: 0.9em; +} + +.doc table th, +.doc table td { + background: transparent; + padding: 0.1em 0.3em; + height: 1.2em; +} + +.doc table th { + text-align: center; + letter-spacing: 0.1em; +} + +.doc pre { + border-radius: 2px; + font-size: 1.1em; + letter-spacing: 0.05em; + background: #eee; + /* Fallback value */ + background: var(--highlight-color); +} + +.doc code { + border-radius: 2px; + padding: 0 0.2em; + letter-spacing: 0.05em; + background: #eee; + /* Fallback value */ + background: var(--highlight-color); +} + +.doc li { + list-style-position: inside; + list-style-type: square; +} + +.doc img, +.doc table, +.doc table th, +.doc table td { + border-width: 1px; + border-style: solid; + border-color: #ccc; + /* Fallback value */ + border-color: var(--secondary-color); +} + +.doc hr { + background: #ccc; + /* Fallback value */ + background: var(--secondary-color); + height: 1px; + border: 0; +} \ No newline at end of file diff --git a/vscode-client/rendererHtml/css/log.csstemp b/vscode-client/rendererHtml/css/log.csstemp new file mode 100644 index 00000000..3302b83b --- /dev/null +++ b/vscode-client/rendererHtml/css/log.csstemp @@ -0,0 +1,302 @@ +/* Icons are from Open Iconic . + Licensed under the MIT License. */ +:host { + --icon-filter: invert(0); + --icon-highlight: var(--secondary-color); + --elapsed-color: #666; + --block-highlight: #ccc; +} + +@media (prefers-color-scheme: dark) { + [data-theme="dark"] { + --icon-filter: invert(1); + --icon-highlight: #a39990; + --elapsed-color: #999; + --block-highlight: #2c3237; + } +} + +/* Containers */ +.suite, +.test, +#errors { + border-color: #ccc; + /* Fallback value */ + border-color: var(--secondary-color); + border-width: 1px; + border-style: solid; + padding: 0.3em 0.2em; + margin: 0.2em 0; +} + +.test { + border-style: dashed; +} + +#errors, +.messages { + width: 100%; + border-spacing: 0; +} + +.children { + display: none; + margin-left: 1.4em; +} + +.suite, +.test, +.keyword { + margin-left: -0.2em; +} + +#s1, +.suite>.children>.keyword { + margin-left: 0; +} + +/* Suite, test and kw headers */ +.element-header { + border: 1px solid transparent; + border-radius: 2px; + position: relative; +} + +.element-header:hover { + cursor: pointer; + background-color: #eee; + /* Fallback value */ + background-color: var(--highlight-color); + border-color: #ccc; + /* Fallback value */ + border-color: var(--secondary-color); +} + +.element-header-toggle { + position: absolute; + left: 3px; + top: 5px; + background-repeat: no-repeat; + background-position: center; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAQAAABKxSfDAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfeCR0JChSkZz20AAAAGklEQVQI12NgQAKMDKzInP8IDhOqMk4G7AAANQwBE427PYUAAAAASUVORK5CYII=); + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCA4IDgiPgogIDxwYXRoIGQ9Ik0wIDB2Mmg4di0yaC04eiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzKSIgLz4KPC9zdmc+), none; + filter: var(--icon-filter); + height: 10px; + width: 10px; + background-size: 6px 6px; + border-color: #ccc; + /* Fallback value */ + border-color: var(--icon-highlight); + border-width: 1px; + border-style: solid; + border-radius: 2px; +} + +.closed>.element-header-toggle { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAQAAABKxSfDAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfeCR0JCDHdVYtxAAAAM0lEQVQI103MMQqAMBQFwVHyITaB3P+W1sKzSBC3mW6hRFw0pUB5DvF1bu9FN0RM3X/wAk98CUnvFTakAAAAAElFTkSuQmCC); + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCA4IDgiPgogIDxwYXRoIGQ9Ik0zIDB2M2gtM3YyaDN2M2gydi0zaDN2LTJoLTN2LTNoLTJ6IiAvPgo8L3N2Zz4=), none; +} + +.element-header:hover>.element-header-toggle { + background-color: #ccc; + /* Fallback value */ + background-color: var(--icon-highlight); +} + +.element-header-right:hover~.element-header-toggle { + background-color: transparent; +} + +.element-header-left { + padding: 3px 80px 3px 20px; +} + +.element-header-right { + position: absolute; + right: 0; + top: 0; + padding: 3px; + cursor: default; +} + +.element-header .label { + margin-right: 0.5em; +} + +.name { + font-weight: bold; + white-space: pre-wrap; +} + +.arg, +.assign { + white-space: pre-wrap; +} + +.elapsed { + float: right; + color: #666; + /* Fallback value */ + color: var(--elapsed-color); + padding-left: 1em; +} + +.link { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAHlJREFUGJVtzrEJwmAQBtCn6ASuIKTIBhY2gmghBiJYB1udwk10B8FJbKMBcQFbtbkfJHrVwfu+4/idJR64Y9H7E3higj5O3S8Y44ApLnjhnXCNGhV2yNGggDJwiC02gavUbpDFvscRo4QdXOMKDHBufz3HLYKzNn4AbSkV3fncGQYAAAAASUVORK5CYII=); + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCA4IDgiPgogIDxwYXRoIGQ9Ik01Ljg4LjAzYy0uMTguMDEtLjM2LjAzLS41My4wOS0uMjcuMS0uNTMuMjUtLjc1LjQ3YS41LjUgMCAxIDAgLjY5LjY5Yy4xMS0uMTEuMjQtLjE3LjM4LS4yMi4zNS0uMTIuNzgtLjA3IDEuMDYuMjIuMzkuMzkuMzkgMS4wNCAwIDEuNDRsLTEuNSAxLjVjLS40NC40NC0uOC40OC0xLjA2LjQ3LS4yNi0uMDEtLjQxLS4xMy0uNDEtLjEzYS41LjUgMCAxIDAtLjUuODhzLjM0LjIyLjg0LjI1Yy41LjAzIDEuMi0uMTYgMS44MS0uNzhsMS41LTEuNWMuNzgtLjc4Ljc4LTIuMDQgMC0yLjgxLS4yOC0uMjgtLjYxLS40NS0uOTctLjUzLS4xOC0uMDQtLjM4LS4wNC0uNTYtLjAzem0tMiAyLjMxYy0uNS0uMDItMS4xOS4xNS0xLjc4Ljc1bC0xLjUgMS41Yy0uNzguNzgtLjc4IDIuMDQgMCAyLjgxLjU2LjU2IDEuMzYuNzIgMi4wNi40Ny4yNy0uMS41My0uMjUuNzUtLjQ3YS41LjUgMCAxIDAtLjY5LS42OWMtLjExLjExLS4yNC4xNy0uMzguMjItLjM1LjEyLS43OC4wNy0xLjA2LS4yMi0uMzktLjM5LS4zOS0xLjA0IDAtMS40NGwxLjUtMS41Yy40LS40Ljc1LS40NSAxLjAzLS40NC4yOC4wMS40Ny4wOS40Ny4wOWEuNS41IDAgMSAwIC40NC0uODhzLS4zNC0uMi0uODQtLjIyeiIKICAvPgo8L3N2Zz4=), none; + filter: var(--icon-filter); +} + +.expand { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAADtJREFUGJVjYCACKDAwMByA0ljFDjAwMPxnYGB4ABVQgLL/Q+VQBB6gseGmIivCkERXhFUSWRFOSawAAEl7E3uv1iMcAAAAAElFTkSuQmCC); + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCA4IDgiPgogIDxwYXRoIGQ9Ik0xLjUgMGwtMS41IDEuNSA0IDQgNC00LTEuNS0xLjUtMi41IDIuNS0yLjUtMi41eiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgLz4KPC9zdmc+), none; + filter: var(--icon-filter); +} + +.collapse { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAC5JREFUGJVjYCARNEAxTsn/UIyhCFkSQxG6ThQ+C5IpjWhG1yNb4YDFTdjEMAEACi8Q++9Y9TAAAAAASUVORK5CYII=); + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCA4IDgiPgogIDxwYXRoIGQ9Ik00IDBsLTQgNCAxLjUgMS41IDIuNS0yLjUgMi41IDIuNSAxLjUtMS41LTQtNHoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMSkiIC8+Cjwvc3ZnPg==), none; + filter: var(--icon-filter); +} + +.expand, +.collapse, +.link { + float: left; + display: block; + visibility: hidden; + margin: 0 4px; + height: 14px; + width: 14px; + background-size: 8px 8px; + background-repeat: no-repeat; + background-position: center; + border-color: #ccc; + /* Fallback value */ + border-color: var(--icon-highlight); + border-width: 1px; + border-style: solid; + border-radius: 2px; +} + +.link { + background-size: 10px 10px; +} + +.element-header:hover .collapse, +.element-header:hover .expand, +.element-header:hover .link { + visibility: visible; +} + +.expand:hover, +.collapse:hover, +.link:hover { + background-color: #ccc; + /* Fallback value */ + background-color: var(--icon-highlight); +} + +/* Messages and errors */ +.messages .time, +.messages .message { + font-family: monospace; + font-size: 1.1em; +} + +#errors .message { + font-family: monospace; + font-size: 1.2em; +} + +.message-row { + height: 20px; +} + +.time { + width: 7.5em; +} + +.error-time { + width: 11em; + font-size: 0.9em; + white-space: nowrap; +} + +.level { + width: 5em; + text-align: center; +} + +.select-message { + width: 24px; +} + +.select-message>div { + float: right; + margin-right: 2px; + height: 16px; + width: 16px; + background-size: 12px 12px; + background-repeat: no-repeat; + background-position: center; +} + +.message-row:hover .select-message div { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfeCR0MOzhWKZQOAAAASUlEQVQY032PsRHAIAwDX9BkicD+W8UMEqegAQJWKZ/+3sLZJhFGQEZzNaIa4ibh66En867VNaIeoP5WppNuIGoAlOm3g5VC1AdYeQv1BZPRSgAAAABJRU5ErkJggg==); + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCA4IDgiPgogIDxwYXRoIGQ9Ik0wIDB2MWg4di0xaC04em0wIDJ2MWg2di0xaC02em0wIDJ2MWg4di0xaC04em0wIDJ2MWg2di0xaC02eiIgLz4KPC9zdmc+), none; + filter: var(--icon-filter); + border-color: #ccc; + /* Fallback value */ + border-color: var(--icon-highlight); + border-width: 1px; + border-style: solid; + border-radius: 2px; +} + +.select-message:hover div { + background-color: #ccc; + /* Fallback value */ + background-color: var(--icon-highlight); + cursor: pointer; +} + +/* Message tables - these MUST NOT be combined together because otherwise + dynamically altering them based on visible log level is not possible. */ +.trace-message { + display: table; +} + +.debug-message { + display: table; +} + +/* Metadata */ +.metadata { + width: 100%; + border-spacing: 0.2em; +} + +.metadata th { + width: 12em; + vertical-align: top; + text-align: left; +} + +.metadata td { + vertical-align: top; +} + +.keyword-metadata { + font-size: 0.9em; +} + +/* Custom styles for statistics */ +#total-stats tr:hover, +#tag-stats tr:hover { + cursor: default; +} + +.highlighted { + background-color: var(--block-highlight); +} \ No newline at end of file diff --git a/vscode-client/rendererHtml/css/print.csstemp b/vscode-client/rendererHtml/css/print.csstemp new file mode 100644 index 00000000..dce25883 --- /dev/null +++ b/vscode-client/rendererHtml/css/print.csstemp @@ -0,0 +1,58 @@ +body { + background: white !important; + padding: 0; + font-size: 8pt; +} + +a:link, +a:visited { + color: black; +} + +#header { + width: auto; +} + +.details, +.statistics { + width: 100%; +} + +#generated-ago, +#top-right-header, +#normal-selector, +#search-buttons, +.folding-button, +.expand, +.hidden, +.details-col-toggle { + display: none; +} + +.element-header-text, +.children { + margin: 0; +} + +#test-details { + border-collapse: collapse; + background: white; +} + +#test-details th, +#test-details td { + border: 1px solid #ccc; +} + +.details-col-header { + padding: 0; +} + +#print-selector { + display: table-cell; +} + +.tablesorter-header { + background-image: none; + background: #ddd !important; +} \ No newline at end of file diff --git a/vscode-client/rendererHtml/index.tsx b/vscode-client/rendererHtml/index.tsx new file mode 100644 index 00000000..7faeae41 --- /dev/null +++ b/vscode-client/rendererHtml/index.tsx @@ -0,0 +1,75 @@ +import commonCss from "./css/common.csstemp"; +import logCss from "./css/log.csstemp"; +import printCss from "./css/print.csstemp"; +import docFormatting from "./css/doc_formatting.csstemp"; + +import jqueryJs from "./js/jquery.min.jstemp"; +import logJs from "./js/log.jstemp"; +import utilJs from "./js/util.jstemp"; + +import type { ActivationFunction } from "vscode-notebook-renderer"; + +export const activate: ActivationFunction = (_context) => { + const commonCssStyle = new CSSStyleSheet({ media: "all" }); + commonCssStyle.replaceSync(commonCss); + + const logCssStyle = new CSSStyleSheet({ media: "all" }); + logCssStyle.replaceSync(logCss); + + const printCssStyle = new CSSStyleSheet({ media: "print" }); + printCssStyle.replaceSync(printCss); + + const docFormattingStyle = new CSSStyleSheet({ media: "all" }); + docFormattingStyle.replaceSync(docFormatting); + + const jqueryJsScript = document.createElement("script"); + jqueryJsScript.text = jqueryJs; + + const logJsScript = document.createElement("script"); + logJsScript.text = logJs; + + const utilJsScript = document.createElement("script"); + utilJsScript.text = utilJs; + + return { + renderOutputItem(data, element, _signal) { + let shadow = element.shadowRoot; + + if (!shadow) { + shadow = element.attachShadow({ mode: "open" }); + + shadow.adoptedStyleSheets = [ + ...document.adoptedStyleSheets, + commonCssStyle, + logCssStyle, + printCssStyle, + docFormattingStyle, + ]; + + shadow.append(jqueryJsScript.cloneNode(true)); + shadow.append(logJsScript.cloneNode(true)); + shadow.append(utilJsScript.cloneNode(true)); + + const root = document.createElement("div"); + root.id = "root"; + shadow?.append(root); + } + + const root = shadow.querySelector("#root"); + + if (root) { + const themeKind = document.body.getAttribute("data-vscode-theme-kind"); + const darkMode = themeKind?.includes("dark") ?? false; + root.setAttribute("data-theme", darkMode ? "dark" : "light"); + root.innerHTML = data.text(); + const shadow_marker = root.querySelector("div,[data-shadow-marker]"); + if (shadow_marker) { + const shadow_id = shadow_marker.getAttribute("data-shadow-marker"); + if (shadow_id) { + element.setAttribute("data-shadow-id", shadow_id); + } + } + } + }, + }; +}; diff --git a/vscode-client/rendererHtml/js/jquery.min.jstemp b/vscode-client/rendererHtml/js/jquery.min.jstemp new file mode 100644 index 00000000..d467083b --- /dev/null +++ b/vscode-client/rendererHtml/js/jquery.min.jstemp @@ -0,0 +1,2 @@ +/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="

",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 retry + if (children.css('display') != 'block' && retryCount > 0) { + console.debug('expandElement ' + item.id + ' failed! planning retry...'); + setTimeout(function () { expandElement(item, retryCount - 1); }, 0); + return; + } + + element.children('.element-header').removeClass('closed'); +} + +function expandElementWithId(elementid) { + expandElement(window.testdata.findLoaded(elementid)); +} + +function expandElementsWithIds(ids) { + util.map(ids, expandElementWithId); +} + +function loadAndExpandElementIds(ids) { + for (var i in ids) { + window.testdata.ensureLoaded(ids[i], expandElementsWithIds); + } +} + +function expandFailed(element) { + if (element.status == "FAIL" || (element.type == "test" && element.status == "SKIP")) { + window.elementsToExpand = [element]; + window.expandDecider = function (e) { + return e.status == "FAIL"; + }; + expandRecursively(); + } +} + +function expandAll(event, elementId, shadow_root_id) { + try { + var element = shadow_root_id ? $($(`div[data-shadow-id="${shadow_root_id}"]`)[0].shadowRoot).find('#' + elementId) : $('#' + elementId); + + element.find('.children').css({ 'display': 'block' }); + element.find('.element-header').removeClass('closed'); + } finally { + event.stopPropagation(); + } +} + +function expandRecursively() { + if (!window.elementsToExpand.length) + return; + var element = window.elementsToExpand.pop(); + if (!element || elementHiddenByUser(element.id)) { + window.elementsToExpand = []; + return; + } + expandElement(element); + element.callWhenChildrenReady(function () { + var children = element.children(); + for (var i = children.length - 1; i >= 0; i--) { + var child = children[i]; + if (child.type != 'message' && window.expandDecider(child)) + window.elementsToExpand.push(child); + } + if (window.elementsToExpand.length) + setTimeout(expandRecursively, 0); + }); +} + +function elementHiddenByUser(id) { + var element = $('#' + id); + return !element.is(":visible"); +} + +function collapseAll(event, elementId, shadow_root_id) { + try { + var element = shadow_root_id ? $($(`div[data-shadow-id="${shadow_root_id}"]`)[0].shadowRoot).find('#' + elementId) : $('#' + elementId); + + element.find('.children').css({ 'display': 'none' }); + element.find('.element-header').addClass('closed'); + } finally { + event.stopPropagation(); + } +} + +function logLevelSelected(level) { + var anchors = getViewAnchorElements(); + setMessageVisibility(level); + scrollToShortestVisibleAnchorElement(anchors); +} + +function getViewAnchorElements() { + var elem1 = $(document.elementFromPoint(100, 0)); + var elem2 = $(document.elementFromPoint(100, 20)); + return [elem1, elem2]; +} + +function scrollToShortestVisibleAnchorElement(anchors) { + anchors = util.map(anchors, closestVisibleParent); + var shortest = anchors[0]; + for (var i = 1; i < anchors.length; i++) + if (shortest.height() > anchors[i].height()) + shortest = anchors[i]; + shortest.get()[0].scrollIntoView(true); +} + +function setMessageVisibility(level) { + level = parseInt(level); + changeClassDisplay(".trace-message", level <= LEVELS.TRACE); + changeClassDisplay(".debug-message", level <= LEVELS.DEBUG); + changeClassDisplay(".info-message", level <= LEVELS.INFO); +} + +function closestVisibleParent(elem) { + while (!elem.is(":visible")) + elem = elem.parent(); + return elem; +} + +function changeClassDisplay(clazz, visible) { + var styles = document.styleSheets; + for (var i = 0; i < styles.length; i++) { + var rules = getRules(styles[i]); + if (rules === null) + continue; + for (var j = 0; j < rules.length; j++) + if (rules[j].selectorText === clazz) + rules[j].style.display = visible ? "table" : "none"; + } +} + +function getRules(style) { + // With Chrome external CSS files seem to have only null roles and with + // Firefox accessing rules can result to security error. + // Neither of these are a problem on with generated logs. + try { + return style.cssRules || style.rules; + } catch (e) { + return null; + } +} + +function selectMessage(parentId) { + var element = $('#' + parentId).find('.message').get(0); + selectText(element); +} + +function selectText(element) { + // Based on http://stackoverflow.com/questions/985272 + var range, selection; + if (document.body.createTextRange) { // IE 8 + range = document.body.createTextRange(); + range.moveToElementText(element); + range.select(); + } else if (window.getSelection) { // Others + selection = window.getSelection(); + range = document.createRange(); + range.selectNodeContents(element); + selection.removeAllRanges(); + selection.addRange(range); + } +} + +function LogLevelController(minLevel, defaultLevel) { + minLevel = LEVELS[minLevel]; + defaultLevel = LEVELS[defaultLevel]; + + function showLogLevelSelector() { + return minLevel < LEVELS.INFO; + } + + function defaultLogLevel() { + if (minLevel > defaultLevel) + return minLevel; + return defaultLevel; + } + + function showTrace() { + return minLevel == LEVELS.TRACE; + } + + return { + showLogLevelSelector: showLogLevelSelector, + defaultLogLevel: defaultLogLevel, + showTrace: showTrace + }; +} + + +function makeElementVisible(event, elementId, shadowRootId, noHighlight) { + try { + var ids = elementId.split('-'); + var current = []; + while (ids.length) { + current.push(ids.shift()); + openElement(current.join('-'), shadowRootId); + } + var element = shadowRootId ? $($(`div[data-shadow-id="${shadowRootId}"]`)[0].shadowRoot).find('#' + elementId) : $('#' + elementId); + $(element).get(0).scrollIntoView(); + if (!noHighlight) { + highlight(element, shadowRootId); + } + + } finally { + event.stopPropagation(); + } +} + +function highlight(element, shadowRootId) { + var old_elements = shadowRootId ? $($(`div[data-shadow-id="${shadowRootId}"]`)[0].shadowRoot).find(".highlighted") : $(".highlighted"); + old_elements.removeClass("highlighted"); + element.addClass('highlighted'); + // setTimeout(function () { element.removeClass('highlighted'); }, 2000); +} + +function openElement(elementId, shadowRootId) { + var element = shadowRootId ? $($(`div[data-shadow-id="${shadowRootId}"]`)[0].shadowRoot).find('#' + elementId) : $('#' + elementId); + element.children('.children').css({ 'display': 'block' }); + element.children('.element-header').removeClass('closed'); +} \ No newline at end of file diff --git a/vscode-client/rendererHtml/js/util.jstemp b/vscode-client/rendererHtml/js/util.jstemp new file mode 100644 index 00000000..90d60e8a --- /dev/null +++ b/vscode-client/rendererHtml/js/util.jstemp @@ -0,0 +1,224 @@ +window.util = function () { + + function map(elems, func) { + var ret = []; + for (var i = 0, len = elems.length; i < len; i++) { + ret[i] = func(elems[i]); + } + return ret; + } + + function filter(elems, predicate) { + var ret = []; + for (var i = 0, len = elems.length; i < len; i++) { + if (predicate(elems[i])) + ret.push(elems[i]); + } + return ret; + } + + function all(elems) { + for (var i = 0, len = elems.length; i < len; i++) { + if (!elems[i]) + return false; + } + return true; + } + + function any(elems) { + for (var i = 0, len = elems.length; i < len; i++) { + if (elems[i]) + return elems[i]; + } + return false; + } + + function contains(elems, e) { + for (var i = 0, len = elems.length; i < len; i++) { + if (elems[i] == e) + return true; + } + return false; + } + + function last(items) { + return items[items.length-1]; + } + + function unescape(string) { + return string.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); + } + + function escape(string) { + return string.replace(/&/g, '&').replace(//g, '>'); + } + + function normalize(string) { + return string.toLowerCase().replace(/ /g, '').replace(/_/g, ''); + } + + function regexpEscape(string) { + return string.replace(/[-[\]{}()+?*.,\\^$|#]/g, "\\$&"); + } + + function Matcher(pattern) { + pattern = regexpEscape(normalize(pattern)); + var rePattern = '^' + pattern.replace(/\\\?/g, '.').replace(/\\\*/g, '[\\s\\S]*') + '$'; + var regexp = new RegExp(rePattern); + function matches(string) { + return regexp.test(normalize(string)); + } + return { + matches: matches, + matchesAny: function (strings) { + for (var i = 0, len = strings.length; i < len; i++) + if (matches(strings[i])) + return true; + return false; + } + }; + } + + function formatParentName(item) { + var parentName = item.fullName.slice(0, item.fullName.length - item.name.length); + return parentName.replace(/\./g, ' . '); + } + + function timeFromDate(date) { + if (!date) + return 'N/A'; + return formatTime(date.getHours(), date.getMinutes(), + date.getSeconds(), date.getMilliseconds()); + } + + function dateFromDate(date) { + if (!date) + return 'N/A'; + return padTo(date.getFullYear(), 4) + + padTo(date.getMonth() + 1, 2) + + padTo(date.getDate(), 2); + } + + function dateTimeFromDate(date) { + if (!date) + return 'N/A'; + return dateFromDate(date) + ' ' + timeFromDate(date); + } + + function formatTime(hours, minutes, seconds, milliseconds) { + return padTo(hours, 2) + ':' + + padTo(minutes, 2) + ':' + + padTo(seconds, 2) + '.' + + padTo(milliseconds, 3); + } + + function formatElapsed(elapsed) { + var millis = elapsed; + var hours = Math.floor(millis / (60 * 60 * 1000)); + millis -= hours * 60 * 60 * 1000; + var minutes = Math.floor(millis / (60 * 1000)); + millis -= minutes * 60 * 1000; + var seconds = Math.floor(millis / 1000); + millis -= seconds * 1000; + return formatTime(hours, minutes, seconds, millis); + } + + function padTo(number, len) { + var numString = number + ""; + while (numString.length < len) numString = "0" + numString; + return numString; + } + + function timestamp(millis) { + // used also by tools that do not set window.output.baseMillis + var base = window.output ? window.output.baseMillis : 0; + return new Date(base + millis); + } + + function createGeneratedString(timestamp) { + var date = new Date(timestamp); + var dt = dateTimeFromDate(date).slice(0, 17); // drop millis + var offset = date.getTimezoneOffset(); + var sign = offset > 0 ? '-' : '+'; + var hh = Math.floor(Math.abs(offset) / 60); + var mm = Math.abs(offset) % 60; + return dt + ' UTC' + sign + padTo(hh, 2) + ':' + padTo(mm, 2); + } + + function createGeneratedAgoString(timestamp) { + function timeString(time, shortUnit) { + var unit = {y: 'year', d: 'day', h: 'hour', m: 'minute', + s: 'second'}[shortUnit]; + var end = time == 1 ? ' ' : 's '; + return time + ' ' + unit + end; + } + function compensateLeapYears(days, years) { + // Not a perfect algorithm but ought to be enough + return days - Math.floor(years / 4); + } + var generated = Math.round(timestamp / 1000); + var current = Math.round(new Date().getTime() / 1000); + var elapsed = current - generated; + var prefix = ''; + if (elapsed < 0) { + prefix = '- '; + elapsed = Math.abs(elapsed); + } + var secs = elapsed % 60; + var mins = Math.floor(elapsed / 60) % 60; + var hours = Math.floor(elapsed / (60*60)) % 24; + var days = Math.floor(elapsed / (60*60*24)) % 365; + var years = Math.floor(elapsed / (60*60*24*365)); + if (years) { + days = compensateLeapYears(days, years); + return prefix + timeString(years, 'y') + timeString(days, 'd'); + } else if (days) { + return prefix + timeString(days, 'd') + timeString(hours, 'h'); + } else if (hours) { + return prefix + timeString(hours, 'h') + timeString(mins, 'm'); + } else if (mins) { + return prefix + timeString(mins, 'm') + timeString(secs, 's'); + } else { + return prefix + timeString(secs, 's'); + } + } + + function parseQueryString(query) { + var result = {}; + if (!query) + return result; + var params = query.split('&'); + var parts; + function decode(item) { + return decodeURIComponent(item.replace('+', ' ')); + } + for (var i = 0, len = params.length; i < len; i++) { + parts = params[i].split('='); + result[decode(parts.shift())] = decode(parts.join('=')); + } + return result; + } + + return { + map: map, + filter: filter, + all: all, + any: any, + contains: contains, + last: last, + escape: escape, + unescape: unescape, + normalize: normalize, + regexpEscape: regexpEscape, + Matcher: Matcher, + formatParentName: formatParentName, + timeFromDate: timeFromDate, + dateFromDate: dateFromDate, + dateTimeFromDate: dateTimeFromDate, + formatElapsed: formatElapsed, + timestamp: timestamp, + createGeneratedString: createGeneratedString, + createGeneratedAgoString: createGeneratedAgoString, + parseQueryString: parseQueryString + }; +}(); \ No newline at end of file diff --git a/vscode-client/rendererHtml/tsconfig.json b/vscode-client/rendererHtml/tsconfig.json new file mode 100644 index 00000000..cb81bf22 --- /dev/null +++ b/vscode-client/rendererHtml/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "module": "CommonJS", + "target": "ES2022", + "allowJs": false, + "composite": true, + "outDir": "../../out/rendererHtml", + "rootDir": ".", + "lib": [ + "ES2022", + "DOM" + ], + "esModuleInterop": true, + }, + "exclude": [ + "../../node_modules", + ".vscode-test", + ] +} \ No newline at end of file diff --git a/vscode-client/rendererHtml/types.d.ts b/vscode-client/rendererHtml/types.d.ts new file mode 100644 index 00000000..d9c8bd05 --- /dev/null +++ b/vscode-client/rendererHtml/types.d.ts @@ -0,0 +1,9 @@ +declare module "*.csstemp" { + const content: string; + export default content; +} + +declare module "*.jstemp" { + const content: string; + export default content; +} diff --git a/vscode-client/rendererLog/common.css b/vscode-client/rendererLog/common.css new file mode 100644 index 00000000..1c4a5b82 --- /dev/null +++ b/vscode-client/rendererLog/common.css @@ -0,0 +1,156 @@ +:target { + overflow: hidden; +} + +/* Generic and misc styles */ +.result-body { + /* font-family: var(--vscode-font-family); */ + font-family: Helvetica, sans-serif; + color: var(--vscode-robotcode-logForeground); + background-color: var(--vscode-robotcode-logBackground); +} + +.root-container { + overflow-y: auto; + max-height: var(--notebook-cell-output-max-height); +} + +table { + table-layout: fixed; + word-wrap: break-word; + empty-cells: show; +} + +th, +td { + vertical-align: top; +} + + +hr { + height: 1px; + border: 0; +} + +a, +a:link, +a:visited { + text-decoration: none; +} + +a>img { + border-width: 1px !important; + border-style: solid !important; +} + +a:hover, +a:active { + text-decoration: underline; +} + +.parent-name { + font-size: x-small; +} + +.message { + white-space: pre-wrap; +} + +/* Headers */ +#header { + width: 65em; + height: 3em; + margin: 20px 0 6px 0; +} + +h1 { + float: left; + margin: 0 0 0.5em 0; + width: 75%; +} + +h2 { + clear: left; +} + +#generated { + float: right; + text-align: right; + font-size: 0.9em; + white-space: nowrap; +} + +/* Documentation headers */ +.doc>h2 { + font-size: 1.2em; +} + +.doc>h3 { + font-size: 1.1em; +} + +.doc>h4 { + font-size: 1.0em; +} + +.label { + padding: 2px 5px; + font-size: 0.75em; + letter-spacing: 1px; + white-space: nowrap; + border-radius: 3px; + color: var(--vscode-robotcode-logLabelForeground); + background-color: var(--vscode-robotcode-logLabelBackground); +} + +.label.debug, +.label.trace, +.label.error, +.label.keyword { + letter-spacing: 0; +} + +.label.pass, +.label.fail, +.label.error, +.label.skip, +.label.warn { + font-weight: bold; + color: var(--vscode-robotcode-logLabelWarnForeground); + background-color: var(--vscode-robotcode-logLabelWarnBackground); +} + +.label.pass { + background-color: #97bd61; + color: var(--vscode-robotcode-logLabelPassForeground); + background-color: var(--vscode-robotcode-logLabelPassBackground); +} + +.label.fail, +.label.error { + color: var(--vscode-robotcode-logLabelErrorForeground); + background-color: var(--vscode-robotcode-logLabelErrorBackground); +} + +.label.skip, +.label.warn { + background-color: #fed84f; + color: var(--vscode-robotcode-logLabelWarnForeground); + background-color: var(--vscode-robotcode-logLabelWarnBackground); +} + +/* Top right header */ +#top-right-header { + position: fixed; + top: 0; + right: 0; + z-index: 1000; + width: 12em; + text-align: center; +} + +#log-level-selector { + padding: 0.3em 0; + font-size: 0.9em; + border-bottom-left-radius: 4px; +} \ No newline at end of file diff --git a/vscode-client/rendererLog/docFormatting.css b/vscode-client/rendererLog/docFormatting.css new file mode 100644 index 00000000..b47827ad --- /dev/null +++ b/vscode-client/rendererLog/docFormatting.css @@ -0,0 +1,67 @@ +.doc>* { + margin: 0.7em 1em 0.1em 1em; + padding: 0; +} + +.doc>p, +.doc>h1, +.doc>h2, +.doc>h3, +.doc>h4 { + margin: 0.7em 0 0.1em 0; +} + +.doc>*:first-child { + margin-top: 0.1em; +} + +.doc table { + background: transparent; + border-collapse: collapse; + empty-cells: show; + font-size: 0.9em; +} + +.doc table th, +.doc table td { + background: transparent; + padding: 0.1em 0.3em; + height: 1.2em; +} + +.doc table th { + text-align: center; + letter-spacing: 0.1em; +} + +.doc pre { + border-radius: 2px; + font-size: 1.1em; + letter-spacing: 0.05em; +} + +.doc code { + border-radius: 2px; + padding: 0 0.2em; + letter-spacing: 0.05em; +} + +.doc li { + list-style-position: inside; + list-style-type: square; +} + +.doc img, +.doc table, +.doc table th, +.doc table td { + border-width: 1px; + border-style: solid; +} + +.doc hr { + background: #ccc; + /* Fallback value */ + height: 1px; + border: 0; +} \ No newline at end of file diff --git a/vscode-client/rendererLog/index.tsx b/vscode-client/rendererLog/index.tsx new file mode 100644 index 00000000..8fa10cae --- /dev/null +++ b/vscode-client/rendererLog/index.tsx @@ -0,0 +1,40 @@ +import type { ActivationFunction } from "vscode-notebook-renderer"; +import { render } from "preact"; +import { Renderer } from "./renderer"; +import commonCss from "./common.css"; +import rendererCss from "./log.css"; +import docFormattingCss from "./docFormatting.css"; + +export const activate: ActivationFunction = (_context) => { + const commonStyle = new CSSStyleSheet({ media: "all" }); + commonStyle.replaceSync(commonCss); + + const logStyle = new CSSStyleSheet({ media: "all" }); + logStyle.replaceSync(rendererCss); + + const docFormattingStyle = new CSSStyleSheet({ media: "all" }); + docFormattingStyle.replaceSync(docFormattingCss); + + return { + renderOutputItem(data, element, _signal) { + let shadow = element.shadowRoot; + + if (!shadow) { + shadow = element.attachShadow({ mode: "open" }); + + shadow.adoptedStyleSheets = [...document.adoptedStyleSheets, commonStyle, logStyle, docFormattingStyle]; + + const root = document.createElement("div"); + root.id = "root"; + + shadow?.append(root); + } + + const root = shadow.querySelector("#root"); + + if (root) { + render(, root); + } + }, + }; +}; diff --git a/vscode-client/rendererLog/log.css b/vscode-client/rendererLog/log.css new file mode 100644 index 00000000..850f3608 --- /dev/null +++ b/vscode-client/rendererLog/log.css @@ -0,0 +1,277 @@ +.suite, +.test, +#errors { + border-width: 1px; + border-style: solid; + padding: 0.3em 0.2em; + margin: 0.2em 0; +} + + +.test { + border-style: dashed; +} + +#errors, +.messages { + width: 100%; + border-spacing: 0; +} + +.children { + margin-left: 0em; +} + +.children.collapsible { + margin-left: 1.4em; +} + + +.children[data-collapsed=true] { + display: none; +} + +.children[data-collapsed=false] { + display: block; +} + + +.suite, +.test, +.keyword { + border-left-width: 1px; + border-left-style: solid; + border-color: transparent; +} + +.keyword:hover { + border-left-style: dashed; + border-color: inherit; +} + +#s1, +.suite>.children>.keyword { + margin-left: 0; +} + +/* Suite, test and kw headers */ +.expander-header { + border-width: 0px; + border-radius: 5px; + position: relative; + margin-left: 2px; +} + +.expander-root-header { + border-width: 0px; + border-radius: 5px; + position: relative; + margin-left: 2px; +} + +.expander-header:hover { + background-color: var(--vscode-robotcode-expanderHeaderHoverBackground); + outline: 1px dashed var(--vscode-robotcode-expanderHeaderHoverOutline); + outline-offset: -1px; +} + +.expander-header:focus { + color: var(--vscode-robotcode-expanderHeaderFocusForeground); + background-color: var(--vscode-robotcode-expanderHeaderFocusBackground); + outline: 1px solid var(--vscode-robotcode-expanderHeaderFocusOutline); + outline-offset: -1px; +} + +.expander-header:focus:hover { + color: var(--vscode-robotcode-expanderHeaderFocusForeground); + background-color: var(--vscode-robotcode-expanderHeaderHoverBackground); + outline: 1px solid var(--vscode-robotcode-expanderHeaderFocusOutline); + outline-offset: -1px; +} + +.expander-header-left { + cursor: pointer; + padding: 3px 80px 3px 20px; +} + +.expander-root-header-left { + padding: 3px 80px 3px 20px; + height: 1em; +} + +.expander-header-right { + position: absolute; + right: 0px; + top: 2px; + cursor: default; +} + +.expander-header .label { + margin-right: 0.5em; +} + +.name { + font-weight: bold; + white-space: pre-wrap; +} + +.arg, +.assign { + white-space: pre-wrap; +} + +.elapsed { + float: right; + padding-left: 1em; +} + +.expander-icon { + color: var(--vscode-robotcode-expanderIconForeground); + text-align: center; + vertical-align: middle; + font-family: monospace; + fill: var(--vscode-icon-foreground); + cursor: pointer; + display: inline-block; + width: 1em; + height: 1em; + padding: 1px; + border-radius: 5px; +} + +.expander-icon:hover { + cursor: pointer; + background-color: var(--vscode-robotcode-expanderIconHoverBackground); + outline: 1px dashed var(--vscode-robotcode-expanderIconHoverOutline); + outline-offset: -1px; +} + +.expander-icon.toggle[data-collapsed=false]::after { + content: '-'; +} + +.expander-icon.toggle[data-collapsed=true]::after { + content: '+'; +} + +.expander-icon.toggle { + margin: 0 auto; + position: absolute; + left: 0px; + top: 3px; +} + +.expander-header .expand-all, +.expander-header .collapse-all, +.expander-header .link, +.expander-root-header .expand-all, +.expander-root-header .collapse-all, +.expander-root-header .link { + visibility: hidden; +} + +.collapse-all::after { + content: 'â–²'; +} + +.expand-all::after { + content: 'â–¼'; +} + +.link::after { + content: '⇗'; +} + +.expander-header:hover .collapse-all, +.expander-header:hover .expand-all, +.expander-header:hover .link, +.expander-root-header:hover .collapse-all, +.expander-root-header:hover .expand-all, +.expander-root-header:hover .link { + visibility: visible; +} + +/* Messages and errors */ +.messages .time, +.messages .message { + font-family: monospace; +} + +#errors .message { + font-family: monospace; +} + +.message-row { + height: 20px; +} + +.time { + width: 5.5em; +} + +.error-time { + width: 11em; + white-space: nowrap; +} + +.level { + width: 5em; + text-align: center; +} + +.select-message { + width: 24px; +} + +.select-message>div { + float: right; + margin-right: 2px; + height: 16px; + width: 16px; + background-size: 12px 12px; + background-repeat: no-repeat; + background-position: center; +} + +.message-row:hover .select-message div { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfeCR0MOzhWKZQOAAAASUlEQVQY032PsRHAIAwDX9BkicD+W8UMEqegAQJWKZ/+3sLZJhFGQEZzNaIa4ibh66En867VNaIeoP5WppNuIGoAlOm3g5VC1AdYeQv1BZPRSgAAAABJRU5ErkJggg==); + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4IiBoZWlnaHQ9IjgiIHZpZXdCb3g9IjAgMCA4IDgiPgogIDxwYXRoIGQ9Ik0wIDB2MWg4di0xaC04em0wIDJ2MWg2di0xaC02em0wIDJ2MWg4di0xaC04em0wIDJ2MWg2di0xaC02eiIgLz4KPC9zdmc+), none; + filter: var(--icon-filter); + border-width: 1px; + border-style: solid; + border-radius: 2px; +} + +.select-message:hover div { + cursor: pointer; +} + +/* Message tables - these MUST NOT be combined together because otherwise + dynamically altering them based on visible log level is not possible. */ +.trace-message { + display: table; +} + +.debug-message { + display: table; +} + +/* Metadata */ +.metadata { + width: 100%; + border-spacing: 0.2em; +} + +.metadata th { + width: 12em; + vertical-align: top; + text-align: left; +} + +.metadata td { + vertical-align: top; +} + +.keyword-metadata { + font-size: 1em; +} \ No newline at end of file diff --git a/vscode-client/rendererLog/renderer.tsx b/vscode-client/rendererLog/renderer.tsx new file mode 100644 index 00000000..ac9a09e3 --- /dev/null +++ b/vscode-client/rendererLog/renderer.tsx @@ -0,0 +1,557 @@ +import { h, Fragment, Component, createRef, createContext, RefObject } from "preact"; + +interface ResultData { + node_type: "message" | "root" | "keyword"; +} + +interface RootResultData extends ResultData { + node_type: "root"; + items: ResultData[]; +} + +interface MessageResultData extends ResultData { + node_type: "message"; + + id: string; + message: string; + level: string; + html: boolean; + timestamp?: string; +} + +interface KeywordResultData extends ResultData { + node_type: "keyword"; + + id: string; + name: string; + owner: string; + source_name: string; + doc: string; + args: string[]; + assign: string[]; + tags: string[]; + timeout?: string; + type: string; + status: string; + start_time: string; + end_time: string; + elapsed_time: number; + + items: ResultData[]; +} + +export interface ExpandableContextType { + registerChild: (ref: RefObject) => void; + unregisterChild: (ref: RefObject) => void; + get parentThis(): RefObject | null; +} + +const ExpandableContext = createContext>({ + registerChild: () => {}, + unregisterChild: () => {}, + get parentThis() { + return null; + }, +}); + +interface ExpandableProps { + header?: string | h.JSX.Element; + collapsed?: boolean; + collapsible?: boolean; + title?: string; + focusable?: boolean; + rootContainer?: boolean; +} + +class Expandable extends Component { + private childRefs: RefObject[] = []; + private ref: RefObject = createRef(); + private childrenRef = createRef(); + private togglerRef = createRef(); + private headerRef = createRef(); + + public registerChild(ref: RefObject): void { + if (ref && !this.childRefs.includes(ref)) { + this.childRefs.push(ref); + } + } + + public unregisterChild(ref: RefObject): void { + this.childRefs = this.childRefs.filter((childRef) => childRef !== ref); + } + + get isCollapsible(): boolean { + return this.props.collapsible !== false ? true : false; + } + + get isFocusable(): boolean { + return this.props.focusable !== false ? true : false; + } + + get isCollapsed(): boolean { + return this.childrenRef.current?.getAttribute("data-collapsed") === "true"; + } + + get isRootContainer(): boolean { + return this.props.rootContainer === true ? true : false; + } + + get isExpanded(): boolean { + return !this.isCollapsed; + } + + componentWillMount?(): void { + try { + const parentContext = this.context as ExpandableContextType; + parentContext?.registerChild(this.ref); + } catch (e) { + console.log(e); + } + } + + get parent(): Expandable | null { + const parentContext = this.context as ExpandableContextType; + return parentContext?.parentThis?.current ? parentContext.parentThis.current : null; + } + + get root(): Expandable | null { + let parent = this.parent; + while (parent) { + if (parent.parent) { + parent = parent.parent; + } else { + return parent; + } + } + return null; + } + + componentDidMount(): void { + this.ref.current = this; + } + + expand(): void { + if (this.isCollapsible) { + this.childrenRef.current?.setAttribute("data-collapsed", "false"); + this.togglerRef.current?.setAttribute("data-collapsed", "false"); + this.props.collapsed = false; + } + } + + collapse(): void { + if (this.isCollapsible) { + this.childrenRef.current?.setAttribute("data-collapsed", "true"); + this.togglerRef.current?.setAttribute("data-collapsed", "true"); + this.props.collapsed = true; + } + } + + toggle(): void { + if (this.isCollapsed) { + this.expand(); + } else { + this.collapse(); + } + } + + expandAll(): void { + this.expand(); + + this.childRefs.forEach((ref) => ref.current?.expandAll()); + } + + collapseAll(onlyChildren?: boolean): void { + if (!onlyChildren) { + this.collapse(); + } + + this.childRefs.forEach((ref) => ref.current?.collapseAll()); + } + + renderHeader(): h.JSX.Element { + { + return {this.props.header ? this.props.header : <> }; + } + } + + renderItems(): h.JSX.Element { + return ( + this.registerChild(c), + unregisterChild: (c) => this.unregisterChild(c), + parentThis: this.ref, + }} + > + {this.props.children} + + ); + } + + isElementInViewport(element: HTMLElement): boolean { + const elementRect = element.getBoundingClientRect(); + const root = this.root?.childrenRef.current?.closest("expandable-root") ?? document.body; + if (root) { + const containerRect = root.getBoundingClientRect(); + + return elementRect.bottom >= containerRect.top && elementRect.top < containerRect.bottom; + } + return ( + elementRect.top >= 0 && + elementRect.left >= 0 && + elementRect.bottom <= window.innerHeight && + elementRect.right <= window.innerWidth + ); + } + + ensureElementInView(element: HTMLElement | null | undefined) { + if (element && !this.isElementInViewport(element)) { + element.scrollIntoView({ block: "nearest", inline: "nearest" }); + } + } + + focusHeader(): void { + if (this.isFocusable) { + this.ensureElementInView(this.headerRef.current); + this.headerRef.current?.focus({ preventScroll: true }); + } + } + + handleKeyDown(event: KeyboardEvent): void { + const element = this.headerRef.current; + const shadowRoot = element?.getRootNode() as ShadowRoot | Document; + + if (element && element === shadowRoot.activeElement) { + switch (event.key) { + case "ArrowLeft": + event.stopPropagation(); + if (this.isCollapsed) { + this.parent?.focusHeader(); + } else { + this.collapse(); + } + break; + case "ArrowRight": + event.stopPropagation(); + if (this.isExpanded) { + this.getFirstChild()?.focusHeader(); + } else { + this.expand(); + } + break; + case "ArrowDown": + event.preventDefault(); + event.stopPropagation(); + if (this.isExpanded && this.childRefs.length > 0) { + // Gehe zum ersten Kind, wenn der aktuelle Knoten expandiert ist + this.childRefs[0].current?.focusHeader(); + } else { + let current: Expandable | null = this!; + while (current) { + const parent: Expandable | null = current?.parent; + if (!parent) break; // Wurzel erreicht, nichts mehr zu traversieren + + const index = parent.childRefs.indexOf(current.ref); + if (index < parent.childRefs.length - 1) { + // Gehe zum nächsten Geschwister des Elternknotens + parent.childRefs[index + 1].current?.focusHeader(); + return; + } + // Traverse zur übergeordneten Ebene + current = parent; + } + } + break; + case "ArrowUp": + event.preventDefault(); + event.stopPropagation(); + + if (this.parent) { + const index = this.parent.childRefs.indexOf(this.ref); + + if (index > 0) { + let prevSibling = this.parent.childRefs[index - 1]?.current; + while (prevSibling?.isExpanded && prevSibling.childRefs.length > 0) { + prevSibling = prevSibling.childRefs[prevSibling.childRefs.length - 1]?.current; + } + prevSibling?.focusHeader(); + } else { + this.parent.focusHeader(); + } + } + break; + + case "Home": + if (this.root && this.root.childRefs.length) { + event.preventDefault(); + event.stopPropagation(); + + this.root.getFirstChild()?.focusHeader(); + } + break; + case "End": + if (this.root && this.root.childRefs.length) { + event.preventDefault(); + event.stopPropagation(); + + this.root?.getLastExpandedChild()?.focusHeader(); + } + break; + case "PageUp": + if (this.root && this.root.childRefs.length) { + event.preventDefault(); + event.stopPropagation(); + + this.root.getFirstChild()?.focusHeader(); + } + break; + case "PageDown": + if (this.root && this.root.childRefs.length) { + event.preventDefault(); + event.stopPropagation(); + + this.root?.getLastExpandedChild()?.focusHeader(); + } + break; + default: + break; + } + } + } + + handleWheel(event: WheelEvent): void { + const element = this.childrenRef.current; + + if (element) { + const isAtTop = element.scrollTop === 0 && event.deltaY < 0; + const isAtBottom = element.scrollTop + element.clientHeight >= element.scrollHeight && event.deltaY > 0; + + if (!isAtTop && !isAtBottom) { + event.stopPropagation(); + } + } + } + + getFirstChild(): Expandable | null | undefined { + if (this.childRefs.length > 0) { + return this.childRefs[0].current ?? undefined; + } + return null; + } + + getLastChild(): Expandable | null | undefined { + if (this.childRefs.length > 0) { + return this.childRefs[this.childRefs.length - 1].current ?? undefined; + } + return undefined; + } + + getLastExpandedChild(): Expandable | null | undefined { + let lastChild = this.getLastChild(); + while (lastChild?.isExpanded && lastChild.childRefs.length > 0) { + lastChild = lastChild.getLastChild(); + } + return lastChild; + } + + render(): h.JSX.Element { + return ( + +
{ + this.handleKeyDown(event); + }} + onClick={(event) => { + event.stopPropagation(); + this.toggle(); + this.headerRef.current?.focus(); + }} + > + {this.isRootContainer ? ( +
+ {/* {this.renderHeader()} */} +
+ ) : ( +
+ {this.renderHeader()} +
+ )} + +
+ { + event.stopPropagation(); + this.expandAll(); + }} + /> + { + event.stopPropagation(); + this.collapseAll(); + }} + /> + {/* { + event.stopPropagation(); + this.collapseAll(); + }} + /> */} +
+ {this.isCollapsible ? ( + { + event.stopPropagation(); + this.toggle(); + }} + > + ) : null} +
+ +
{ + if (this.isRootContainer) this.handleWheel(event); + }} + data-collapsed={this.props.collapsed} + // class={`children ${this.isCollapsible ? "collapsible" : ""} ${this.props.collapsed ? "closed" : "open"}`} + class={`children ${this.isCollapsible ? "collapsible" : ""} ${this.isRootContainer ? "root-container" : ""}`} + > + {this.renderItems()} +
+
+ ); + } +} + +Expandable.contextType = ExpandableContext; + +class RootResultRenderer extends Component<{ data: RootResultData }> { + renderItems(): h.JSX.Element { + return {this.props.data.items.map((child) => renderResultData(child))}; + } + + render(): h.JSX.Element { + return ( +
+ + {this.renderItems()} + +
+ ); + } +} + +class MessageResultRenderer extends Component<{ data: MessageResultData }> { + render(): h.JSX.Element { + const level_lower = this.props.data.level.toLocaleLowerCase(); + return ( + + + + + {this.props.data.html ? ( + + ) : ( + + )} + {/* */} + +
{this.props.data.timestamp} + {this.props.data.level} + {this.props.data.message} +
+
+ ); + } +} + +interface KeywordProps extends ExpandableProps { + data: KeywordResultData; +} + +class Keyword extends Component { + renderHeader(): h.JSX.Element { + { + return ( + + + {this.props.data.elapsed_time} + + {this.props.data.type} + {this.props.data.assign.join(" ")} + + {this.props.data.owner ? {this.props.data.owner} . : null} + {this.props.data.name} + +   + {this.props.data.args} + + ); + } + } + + renderItems(): h.JSX.Element { + return ( + + + {this.props.data.doc ? ( + + + + + ) : null} + + {this.props.data.items.map((child) => renderResultData(child))} + + ); + } + + render(): h.JSX.Element { + const result = ( +
+ + {this.renderItems()} + +
+ ); + return result; + } +} + +function renderResultData(data: ResultData): h.JSX.Element { + switch (data.node_type) { + case "root": + return ; + case "message": + return ; + case "keyword": + return ; + default: + return
Unknown node type
; + } +} + +interface RendererProps { + data: ResultData; +} + +export class Renderer extends Component { + render(): h.JSX.Element { + return renderResultData(this.props.data); + } +} diff --git a/vscode-client/rendererLog/tsconfig.json b/vscode-client/rendererLog/tsconfig.json new file mode 100644 index 00000000..775b7ed0 --- /dev/null +++ b/vscode-client/rendererLog/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "target": "ES2022", + "moduleResolution": "NodeNext", + "allowJs": false, + // "composite": true, + "outDir": "../../out/rendererLog", + "rootDir": ".", + "lib": [ + "ES7", + "DOM", + "ES2018", + "ES2019", + "ES2020", + "ES2021", + "ES2022", + ], + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + }, + "exclude": [ + ".vscode-test", + ] +} \ No newline at end of file diff --git a/vscode-client/rendererLog/types.d.ts b/vscode-client/rendererLog/types.d.ts new file mode 100644 index 00000000..f4af437b --- /dev/null +++ b/vscode-client/rendererLog/types.d.ts @@ -0,0 +1,9 @@ +declare module "*.css" { + const classes: string; + export = classes; +} + +declare module "*.ttf" { + const content: File; + export default content; +} diff --git a/vscode-client/test/runTest.ts b/vscode-client/test/runTest.ts deleted file mode 100644 index efca079d..00000000 --- a/vscode-client/test/runTest.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as path from "path"; - -import { runTests } from "@vscode/test-electron"; - -async function main() { - try { - // The folder containing the Extension Manifest package.json - // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath: string = path.resolve(__dirname, "../../"); - - // The path to the extension test script - // Passed to --extensionTestsPath - const extensionTestsPath: string = path.resolve(__dirname, "./suite/index"); - - // Download VS Code, unzip it and run the integration test - await runTests({ extensionDevelopmentPath, extensionTestsPath }); - } catch (err) { - console.error(`Failed to run tests: ${err}`); - process.exit(1); - } -} - -void main(); diff --git a/vscode-client/tsconfig.base.json b/vscode-client/tsconfig.base.json new file mode 100644 index 00000000..8600d85e --- /dev/null +++ b/vscode-client/tsconfig.base.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "sourceMap": true, + "strict": true, + // "experimentalDecorators": true, + // "emitDecoratorMetadata": true, + // "esModuleInterop": true, + // "allowSyntheticDefaultImports": true, + "noImplicitAny": true, + "noImplicitThis": true, + "noUnusedLocals": true, + //"noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "removeComments": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + } +} \ No newline at end of file From e2fbc16a9097662748b9b6b512448f621bacbed9 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 5 Dec 2024 16:55:33 +0100 Subject: [PATCH 10/13] style: enable ruff rules RUF021 and RUF022 --- .../core/src/robotcode/core/concurrent.py | 6 +-- packages/core/src/robotcode/core/event.py | 2 +- .../src/robotcode/core/utils/dataclasses.py | 10 ++-- .../src/robotcode/core/utils/glob_path.py | 4 +- .../core/src/robotcode/core/utils/logging.py | 2 +- .../src/robotcode/debugger/debugger.py | 29 +++++------- .../src/robotcode/jsonrpc2/protocol.py | 25 +++++----- .../language_server/common/parts/documents.py | 2 +- .../language_server/common/server.py | 2 +- .../parts/code_action_refactor.py | 38 ++++++--------- .../robotframework/parts/inlay_hint.py | 2 +- .../robotframework/parts/semantic_tokens.py | 9 ++-- .../plugin/src/robotcode/plugin/__init__.py | 10 ++-- .../robot/diagnostics/diagnostics_modifier.py | 2 +- .../robot/diagnostics/imports_manager.py | 3 +- .../robot/diagnostics/library_doc.py | 47 +++++++++++-------- .../robot/diagnostics/model_helper.py | 5 +- .../robot/src/robotcode/robot/utils/ast.py | 4 +- .../robot/utils/markdownformatter.py | 2 +- .../src/robotcode/runner/cli/__init__.py | 2 +- .../robotcode/runner/cli/discover/discover.py | 2 +- pyproject.toml | 2 +- scripts/generate_rf_options.py | 4 +- src/robotcode/cli/commands/profiles.py | 2 +- .../robotframework/parts/test_foldingrange.py | 13 ++--- 25 files changed, 109 insertions(+), 120 deletions(-) diff --git a/packages/core/src/robotcode/core/concurrent.py b/packages/core/src/robotcode/core/concurrent.py index 55c3624d..ad0d99af 100644 --- a/packages/core/src/robotcode/core/concurrent.py +++ b/packages/core/src/robotcode/core/concurrent.py @@ -145,10 +145,8 @@ def decorator(func: _F) -> _F: def is_threaded_callable(callable: Callable[..., Any]) -> bool: - return ( - getattr(callable, __THREADED_MARKER, False) - or inspect.ismethod(callable) - and getattr(callable, __THREADED_MARKER, False) + return getattr(callable, __THREADED_MARKER, False) or ( + inspect.ismethod(callable) and getattr(callable, __THREADED_MARKER, False) ) diff --git a/packages/core/src/robotcode/core/event.py b/packages/core/src/robotcode/core/event.py index 2b33ed47..f30297f7 100644 --- a/packages/core/src/robotcode/core/event.py +++ b/packages/core/src/robotcode/core/event.py @@ -19,7 +19,7 @@ from typing_extensions import ParamSpec -__all__ = ["event_iterator", "event"] +__all__ = ["event", "event_iterator"] _TResult = TypeVar("_TResult") _TParams = ParamSpec("_TParams") diff --git a/packages/core/src/robotcode/core/utils/dataclasses.py b/packages/core/src/robotcode/core/utils/dataclasses.py index 03e3f5d7..15f623fd 100644 --- a/packages/core/src/robotcode/core/utils/dataclasses.py +++ b/packages/core/src/robotcode/core/utils/dataclasses.py @@ -28,14 +28,14 @@ ) __all__ = [ - "to_snake_case", - "to_camel_case", + "CamelSnakeMixin", + "ValidateMixin", + "as_dict", "as_json", "from_dict", "from_json", - "as_dict", - "ValidateMixin", - "CamelSnakeMixin", + "to_camel_case", + "to_snake_case", ] _RE_SNAKE_CASE_1 = re.compile(r"[\-\.\s]") diff --git a/packages/core/src/robotcode/core/utils/glob_path.py b/packages/core/src/robotcode/core/utils/glob_path.py index 1245bd01..e8564b8a 100644 --- a/packages/core/src/robotcode/core/utils/glob_path.py +++ b/packages/core/src/robotcode/core/utils/glob_path.py @@ -164,7 +164,7 @@ def _iter_files_recursive_re( relative_path = (path / f.name).relative_to(_base_path) if not ignore_patterns or not any( - p.matches(relative_path) and (not p.only_dirs or p.only_dirs and f.is_dir()) + p.matches(relative_path) and (not p.only_dirs or (p.only_dirs and f.is_dir())) for p in cast(Iterable[Pattern], ignore_patterns) ): if f.is_dir(): @@ -177,7 +177,7 @@ def _iter_files_recursive_re( _base_path=_base_path, ) if not patterns or any( - p.matches(relative_path) and (not p.only_dirs or p.only_dirs and f.is_dir()) + p.matches(relative_path) and (not p.only_dirs or (p.only_dirs and f.is_dir())) for p in cast(Iterable[Pattern], patterns) ): yield Path(f).absolute() if absolute else Path(f) diff --git a/packages/core/src/robotcode/core/utils/logging.py b/packages/core/src/robotcode/core/utils/logging.py index aa7fac5c..0e633e6e 100644 --- a/packages/core/src/robotcode/core/utils/logging.py +++ b/packages/core/src/robotcode/core/utils/logging.py @@ -196,7 +196,7 @@ def log( extra: Optional[Mapping[str, object]] = None, **kwargs: Any, ) -> None: - if self.is_enabled_for(level) and condition is not None and condition() or condition is None: + if (self.is_enabled_for(level) and condition is not None and condition()) or condition is None: depth = 0 if context_name is not None: depth = self._measure_contexts.get(context_name, 0) diff --git a/packages/debugger/src/robotcode/debugger/debugger.py b/packages/debugger/src/robotcode/debugger/debugger.py index 7851b1d1..558a20c2 100644 --- a/packages/debugger/src/robotcode/debugger/debugger.py +++ b/packages/debugger/src/robotcode/debugger/debugger.py @@ -1318,11 +1318,8 @@ def message(self, message: Dict[str, Any]) -> None: level = message["level"] current_frame = self.full_stack_frames[0] if self.full_stack_frames else None - if ( - self.output_messages - or current_frame is not None - and current_frame.type != "KEYWORD" - and level in ["FAIL", "ERROR", "WARN"] + if self.output_messages or ( + current_frame is not None and current_frame.type != "KEYWORD" and level in ["FAIL", "ERROR", "WARN"] ): self._send_log_event(message["timestamp"], level, message["message"], "messages") @@ -1599,10 +1596,8 @@ def evaluate( else evaluate_context.variables._global ) if ( - isinstance(context, EvaluateArgumentContext) - and context != EvaluateArgumentContext.REPL - or self.expression_mode - ): + isinstance(context, EvaluateArgumentContext) and context != EvaluateArgumentContext.REPL + ) or self.expression_mode: if expression.startswith("! "): splitted = self.SPLIT_LINE.split(expression[2:].strip()) @@ -1635,13 +1630,15 @@ def run_kw() -> Any: result = vars.replace_scalar(expression) except VariableError: if context is not None and ( - isinstance(context, EvaluateArgumentContext) - and ( - context - in [ - EvaluateArgumentContext.HOVER, - EvaluateArgumentContext.WATCH, - ] + ( + isinstance(context, EvaluateArgumentContext) + and ( + context + in [ + EvaluateArgumentContext.HOVER, + EvaluateArgumentContext.WATCH, + ] + ) ) or context in [ diff --git a/packages/jsonrpc2/src/robotcode/jsonrpc2/protocol.py b/packages/jsonrpc2/src/robotcode/jsonrpc2/protocol.py index 338144e7..4930c962 100644 --- a/packages/jsonrpc2/src/robotcode/jsonrpc2/protocol.py +++ b/packages/jsonrpc2/src/robotcode/jsonrpc2/protocol.py @@ -40,24 +40,24 @@ from robotcode.core.utils.logging import LoggingDescriptor __all__ = [ - "JsonRPCErrors", - "JsonRPCMessage", - "JsonRPCNotification", - "JsonRPCRequest", - "JsonRPCResponse", + "GenericJsonRPCProtocolPart", + "InvalidProtocolVersionError", "JsonRPCError", + "JsonRPCErrorException", "JsonRPCErrorObject", - "JsonRPCProtocol", + "JsonRPCErrors", "JsonRPCException", + "JsonRPCMessage", + "JsonRPCNotification", "JsonRPCParseError", - "InvalidProtocolVersionError", - "rpc_method", - "RpcRegistry", + "JsonRPCProtocol", "JsonRPCProtocolPart", + "JsonRPCRequest", + "JsonRPCResponse", "ProtocolPartDescriptor", - "GenericJsonRPCProtocolPart", + "RpcRegistry", "TProtocol", - "JsonRPCErrorException", + "rpc_method", ] _T = TypeVar("_T") @@ -278,8 +278,7 @@ def get_methods(obj: Any) -> Dict[str, RpcMethodEntry]: iter_methods( obj, lambda m2: isinstance(m2, RpcMethod) - or inspect.ismethod(m2) - and isinstance(m2.__func__, RpcMethod), + or (inspect.ismethod(m2) and isinstance(m2.__func__, RpcMethod)), ), ) } diff --git a/packages/language_server/src/robotcode/language_server/common/parts/documents.py b/packages/language_server/src/robotcode/language_server/common/parts/documents.py index e92b3085..8989efda 100644 --- a/packages/language_server/src/robotcode/language_server/common/parts/documents.py +++ b/packages/language_server/src/robotcode/language_server/common/parts/documents.py @@ -40,7 +40,7 @@ from robotcode.language_server.common.protocol import LanguageServerProtocol -__all__ = ["TextDocumentProtocolPart", "LanguageServerDocumentError"] +__all__ = ["LanguageServerDocumentError", "TextDocumentProtocolPart"] class LanguageServerDocumentError(JsonRPCException): diff --git a/packages/language_server/src/robotcode/language_server/common/server.py b/packages/language_server/src/robotcode/language_server/common/server.py index 666ee37c..94e189d5 100644 --- a/packages/language_server/src/robotcode/language_server/common/server.py +++ b/packages/language_server/src/robotcode/language_server/common/server.py @@ -6,7 +6,7 @@ from .protocol import LanguageServerProtocol -__all__ = ["LanguageServerBase", "TCP_DEFAULT_PORT"] +__all__ = ["TCP_DEFAULT_PORT", "LanguageServerBase"] TCP_DEFAULT_PORT = 6610 diff --git a/packages/language_server/src/robotcode/language_server/robotframework/parts/code_action_refactor.py b/packages/language_server/src/robotcode/language_server/robotframework/parts/code_action_refactor.py index 387311a1..741bf417 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/parts/code_action_refactor.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/parts/code_action_refactor.py @@ -194,23 +194,18 @@ def get_valid_nodes_in_range(self, model: ast.AST, range: Range, also_return: bo r = range_from_node(node, skip_non_data=True, allow_comments=True) if r.is_in_range(range): - if ( - isinstance( - node, - ( - Fixture, - Documentation, - MultiValue, - SingleValue, - TestCaseName, - KeywordName, - TemplateArguments, - ), - ) - or also_return - and get_robot_version() >= (5, 0, 0) - and isinstance(node, ReturnStatement) - ): + if isinstance( + node, + ( + Fixture, + Documentation, + MultiValue, + SingleValue, + TestCaseName, + KeywordName, + TemplateArguments, + ), + ) or (also_return and get_robot_version() >= (5, 0, 0) and isinstance(node, ReturnStatement)): return [] result.append(node) @@ -246,8 +241,7 @@ def get_valid_nodes_in_range(self, model: ast.AST, range: Range, also_return: bo n for n in result if isinstance(n, (IfHeader, ElseIfHeader, ElseHeader, ForHeader, End)) - or get_robot_version() >= (5, 0) - and isinstance(n, (WhileHeader, TryHeader, ExceptHeader, FinallyHeader)) + or (get_robot_version() >= (5, 0) and isinstance(n, (WhileHeader, TryHeader, ExceptHeader, FinallyHeader))) ): return [] @@ -255,10 +249,8 @@ def get_valid_nodes_in_range(self, model: ast.AST, range: Range, also_return: bo n for n in result if isinstance(n, (Continue, Break)) - or isinstance(n, Try) - and n.type in [RobotToken.EXCEPT, RobotToken.FINALLY, RobotToken.ELSE] - or also_return - and isinstance(n, ReturnStatement) + or (isinstance(n, Try) and n.type in [RobotToken.EXCEPT, RobotToken.FINALLY, RobotToken.ELSE]) + or (also_return and isinstance(n, ReturnStatement)) ): return [] diff --git a/packages/language_server/src/robotcode/language_server/robotframework/parts/inlay_hint.py b/packages/language_server/src/robotcode/language_server/robotframework/parts/inlay_hint.py index eed9d5e3..0850edbd 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/parts/inlay_hint.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/parts/inlay_hint.py @@ -69,7 +69,7 @@ def _find_method(self, cls: Type[Any]) -> Optional[_HandlerMethod]: @_logger.call def collect(self, sender: Any, document: TextDocument, range: Range) -> Optional[List[InlayHint]]: config = self.get_config(document) - if config is None or not config.parameter_names and not config.namespaces: + if config is None or (not config.parameter_names and not config.namespaces): return None model = self.parent.documents_cache.get_model(document, False) diff --git a/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py b/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py index 517ede74..a8569cfe 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/parts/semantic_tokens.py @@ -620,8 +620,7 @@ def generate_sem_sub_tokens( if ( yield_arguments or token.type != Token.ARGUMENT - or token.type != Token.NAME - and cached_isinstance(node, Metadata) + or (token.type != Token.NAME and cached_isinstance(node, Metadata)) ): yield SemTokenInfo.from_token(token, sem_type, sem_mod, col_offset, length) @@ -632,10 +631,8 @@ def generate_sem_tokens( namespace: Namespace, builtin_library_doc: Optional[LibraryDoc], ) -> Iterator[SemTokenInfo]: - if ( - token.type in {Token.ARGUMENT, Token.TESTCASE_NAME, Token.KEYWORD_NAME} - or token.type == Token.NAME - and cached_isinstance(node, VariablesImport, LibraryImport, ResourceImport) + if token.type in {Token.ARGUMENT, Token.TESTCASE_NAME, Token.KEYWORD_NAME} or ( + token.type == Token.NAME and cached_isinstance(node, VariablesImport, LibraryImport, ResourceImport) ): if ( cached_isinstance(node, Variable) and token.type == Token.ARGUMENT and node.name and node.name[0] == "&" diff --git a/packages/plugin/src/robotcode/plugin/__init__.py b/packages/plugin/src/robotcode/plugin/__init__.py index ad398603..30ae09e9 100644 --- a/packages/plugin/src/robotcode/plugin/__init__.py +++ b/packages/plugin/src/robotcode/plugin/__init__.py @@ -27,13 +27,13 @@ from robotcode.core.utils.dataclasses import as_dict, as_json __all__ = [ - "hookimpl", - "CommonConfig", - "pass_application", "Application", - "UnknownError", - "OutputFormat", "ColoredOutput", + "CommonConfig", + "OutputFormat", + "UnknownError", + "hookimpl", + "pass_application", ] F = TypeVar("F", bound=Callable[..., Any]) diff --git a/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py b/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py index b4436c19..a48fc2b5 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py +++ b/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py @@ -209,7 +209,7 @@ def modify_diagnostic(self, diagnostic: Diagnostic) -> Optional[Diagnostic]: lines = self.rules_and_codes.codes.get(code) - if lines is None or lines is not None and diagnostic.range.start.line not in lines: + if lines is None or (lines is not None and diagnostic.range.start.line not in lines): code = "*" lines = self.rules_and_codes.codes.get(code) diff --git a/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py b/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py index 606063e9..e4b35298 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py +++ b/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py @@ -322,8 +322,7 @@ def check_file_changed(self, changes: List[FileEvent]) -> Optional[FileChangeTyp if ( self._document is not None and (normalized_path(path) == normalized_path(self._document.uri.to_path())) - or self._document is None - ): + ) or self._document is None: self._invalidate() return change.type diff --git a/packages/robot/src/robotcode/robot/diagnostics/library_doc.py b/packages/robot/src/robotcode/robot/diagnostics/library_doc.py index 0b78bff0..4254c2a8 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/library_doc.py +++ b/packages/robot/src/robotcode/robot/diagnostics/library_doc.py @@ -1824,7 +1824,11 @@ def get_library_doc( if module_spec is not None and module_spec.origin else import_name if is_library_by_path(import_name) else None ), - 1 if source is not None or module_spec is not None and module_spec.origin is not None else None, + ( + 1 + if source is not None or (module_spec is not None and module_spec.origin is not None) + else None + ), ) ], python_path=sys.path, @@ -1868,7 +1872,7 @@ def get_library_doc( error_from_exception( e, source or module_spec.origin if module_spec is not None else None, - 1 if source is not None or module_spec is not None and module_spec.origin is not None else None, + 1 if source is not None or (module_spec is not None and module_spec.origin is not None) else None, ) ) @@ -1919,7 +1923,8 @@ def _get(handler: Callable[[], _T]) -> Optional[_T]: source or module_spec.origin if module_spec is not None else None, ( 1 - if source is not None or module_spec is not None and module_spec.origin is not None + if source is not None + or (module_spec is not None and module_spec.origin is not None) else None ), ) @@ -2119,7 +2124,11 @@ def _get_type_docs(keywords: List[Any], custom_converters: List[Any]) -> Set[Rob error_from_exception( e, source or module_spec.origin if module_spec is not None else None, - 1 if source is not None or module_spec is not None and module_spec.origin is not None else None, + ( + 1 + if source is not None or (module_spec is not None and module_spec.origin is not None) + else None + ), ) ) @@ -2412,7 +2421,11 @@ def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any: if module_spec is not None and module_spec.origin else import_name if is_variables_by_path(import_name) else None ), - 1 if source is not None or module_spec is not None and module_spec.origin is not None else None, + ( + 1 + if source is not None or (module_spec is not None and module_spec.origin is not None) + else None + ), ) ] @@ -2432,7 +2445,7 @@ def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any: if module_spec is not None and module_spec.origin else import_name if is_variables_by_path(import_name) else None ), - 1 if source is not None or module_spec is not None and module_spec.origin is not None else None, + 1 if source is not None or (module_spec is not None and module_spec.origin is not None) else None, ) ], python_path=sys.path, @@ -2480,7 +2493,7 @@ def is_file_like(name: Optional[str]) -> bool: return False base, filename = os.path.split(name) - return name.startswith(".") or bool(base) and filename != name + return name.startswith(".") or (bool(base) and filename != name) def iter_module_names(name: Optional[str] = None) -> Iterator[str]: @@ -2522,10 +2535,8 @@ def iter_modules_from_python_path( if e.is_dir(): for f in e.iterdir(): if not f.name.startswith(("_", ".")) and ( - f.is_file() - and f.suffix in ALLOWED_LIBRARY_FILE_EXTENSIONS - or f.is_dir() - and f.suffix not in NOT_WANTED_DIR_EXTENSIONS + (f.is_file() and f.suffix in ALLOWED_LIBRARY_FILE_EXTENSIONS) + or (f.is_dir() and f.suffix not in NOT_WANTED_DIR_EXTENSIONS) ): if f.is_dir(): yield CompleteResult(f.name, CompleteResultKind.MODULE) @@ -2586,8 +2597,7 @@ def complete_library_import( if not f.name.startswith(("_", ".")) and ( (f.is_file() and f.suffix in ALLOWED_LIBRARY_FILE_EXTENSIONS) - or f.is_dir() - and f.suffix not in NOT_WANTED_DIR_EXTENSIONS + or (f.is_dir() and f.suffix not in NOT_WANTED_DIR_EXTENSIONS) ) ] @@ -2606,10 +2616,8 @@ def iter_resources_from_python_path( if e.is_dir(): for f in e.iterdir(): if not f.name.startswith(("_", ".")) and ( - f.is_file() - and f.suffix in ALLOWED_RESOURCE_FILE_EXTENSIONS - or f.is_dir() - and f.suffix not in NOT_WANTED_DIR_EXTENSIONS + (f.is_file() and f.suffix in ALLOWED_RESOURCE_FILE_EXTENSIONS) + or (f.is_dir() and f.suffix not in NOT_WANTED_DIR_EXTENSIONS) ): yield CompleteResult( f.name, @@ -2633,7 +2641,7 @@ def complete_resource_import( name = robot_variables.replace_string(name, ignore_errors=True) - if name is None or not name.startswith(".") and not name.startswith("/") and not name.startswith(os.sep): + if name is None or (not name.startswith(".") and not name.startswith("/") and not name.startswith(os.sep)): result += list(iter_resources_from_python_path(name)) if name is None or name.startswith((".", "/", os.sep)): @@ -2702,8 +2710,7 @@ def complete_variables_import( if not f.name.startswith(("_", ".")) and ( (f.is_file() and f.suffix in ALLOWED_VARIABLES_FILE_EXTENSIONS) - or f.is_dir() - and f.suffix not in NOT_WANTED_DIR_EXTENSIONS + or (f.is_dir() and f.suffix not in NOT_WANTED_DIR_EXTENSIONS) ) ] diff --git a/packages/robot/src/robotcode/robot/diagnostics/model_helper.py b/packages/robot/src/robotcode/robot/diagnostics/model_helper.py index b790e4b4..5c95080e 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/model_helper.py +++ b/packages/robot/src/robotcode/robot/diagnostics/model_helper.py @@ -749,9 +749,8 @@ def get_argument_info_at_position( if argument_token_index < len(tokens) and tokens[argument_token_index].type == Token.ARGUMENT: argument_token = tokens[argument_token_index] - if ( - argument_index < 0 - or argument_token is not None + if argument_index < 0 or ( + argument_token is not None and argument_token.type == Token.ARGUMENT and argument_token.value.startswith(("@{", "&{")) and argument_token.value.endswith("}") diff --git a/packages/robot/src/robotcode/robot/utils/ast.py b/packages/robot/src/robotcode/robot/utils/ast.py index a6731930..bd130b74 100644 --- a/packages/robot/src/robotcode/robot/utils/ast.py +++ b/packages/robot/src/robotcode/robot/utils/ast.py @@ -205,7 +205,7 @@ def get_tokens_at_position(node: Statement, position: Position, include_end: boo return [ t for t in node.tokens - if position.is_in_range(range := range_from_token(t), include_end) or include_end and range.end == position + if position.is_in_range(range := range_from_token(t), include_end) or (include_end and range.end == position) ] @@ -214,7 +214,7 @@ def iter_nodes_at_position(node: ast.AST, position: Position, include_end: bool yield node for n in iter_nodes(node): - if position.is_in_range(range := range_from_node(n), include_end) or include_end and range.end == position: + if position.is_in_range(range := range_from_node(n), include_end) or (include_end and range.end == position): yield n diff --git a/packages/robot/src/robotcode/robot/utils/markdownformatter.py b/packages/robot/src/robotcode/robot/utils/markdownformatter.py index 0c919c4c..efb2d3de 100644 --- a/packages/robot/src/robotcode/robot/utils/markdownformatter.py +++ b/packages/robot/src/robotcode/robot/utils/markdownformatter.py @@ -276,7 +276,7 @@ class ListFormatter(Formatter): _strip_lines = False def _handles(self, line: str) -> bool: - return bool(line.strip().startswith("- ") or line.startswith(" ") and self._lines) + return bool(line.strip().startswith("- ") or (line.startswith(" ") and self._lines)) def format(self, lines: List[str]) -> str: items = ["- %s" % _line_formatter.format(line) for line in self._combine_lines(lines)] diff --git a/packages/runner/src/robotcode/runner/cli/__init__.py b/packages/runner/src/robotcode/runner/cli/__init__.py index 6b7f913b..a0005e93 100644 --- a/packages/runner/src/robotcode/runner/cli/__init__.py +++ b/packages/runner/src/robotcode/runner/cli/__init__.py @@ -4,4 +4,4 @@ from .robot import robot from .testdoc import testdoc -__all__ = ["robot", "libdoc", "rebot", "testdoc", "discover"] +__all__ = ["discover", "libdoc", "rebot", "robot", "testdoc"] diff --git a/packages/runner/src/robotcode/runner/cli/discover/discover.py b/packages/runner/src/robotcode/runner/cli/discover/discover.py index 9a40135b..56fc6d5a 100644 --- a/packages/runner/src/robotcode/runner/cli/discover/discover.py +++ b/packages/runner/src/robotcode/runner/cli/discover/discover.py @@ -72,7 +72,7 @@ def _patch() -> None: __patched = True if get_robot_version() < (6, 1): - if get_robot_version() > (5, 0) and get_robot_version() < (6, 0) or get_robot_version() < (5, 0): + if (get_robot_version() > (5, 0) and get_robot_version() < (6, 0)) or get_robot_version() < (5, 0): from robot.running.builder.testsettings import ( # pyright: ignore[reportMissingImports] TestDefaults, ) diff --git a/pyproject.toml b/pyproject.toml index 3f3a585e..540fe879 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -175,7 +175,7 @@ target-version = "py38" extend-exclude = ["bundled/libs", ".hatch"] [tool.ruff.lint] -ignore = ["E741", "N805", "N999", "RUF012", "RUF006", "ISC001", "RUF021", "RUF022"] +ignore = ["E741", "N805", "N999", "RUF012", "RUF006", "ISC001"] select = [ "E", "F", diff --git a/scripts/generate_rf_options.py b/scripts/generate_rf_options.py index 978673b9..8330322f 100644 --- a/scripts/generate_rf_options.py +++ b/scripts/generate_rf_options.py @@ -164,7 +164,7 @@ def get_type( has_literal = [x for x in param_splitted if ":" not in x] has_pattern = [x for x in param_splitted if ":" in x] base_type = ( - ("Union[str, " if has_literal and has_pattern or len(has_pattern) > 1 else "") + ("Union[str, " if (has_literal and has_pattern) or len(has_pattern) > 1 else "") + (("Literal[" + ", ".join([f'"{x}"' for x in has_literal]) + "]") if has_literal else "") + ( ( @@ -176,7 +176,7 @@ def get_type( if has_pattern else "" ) - + ("]" if has_literal and has_pattern or len(has_pattern) > 1 else "") + + ("]" if (has_literal and has_pattern) or len(has_pattern) > 1 else "") ) elif len(param_splitted := param.split(":")) > 1: diff --git a/src/robotcode/cli/commands/profiles.py b/src/robotcode/cli/commands/profiles.py index 75c9918a..ea32c45f 100644 --- a/src/robotcode/cli/commands/profiles.py +++ b/src/robotcode/cli/commands/profiles.py @@ -102,7 +102,7 @@ def list(app: Application, paths: List[Path], show_hidden: bool = False, sort_by "precedence": v.precedence, } for k, v in (config.profiles or {}).items() - if show_hidden or not k.startswith("_") and not v.hidden + if show_hidden or (not k.startswith("_") and not v.hidden) ], key=( (lambda v: cast(Any, str(v.get("name", "")))) diff --git a/tests/robotcode/language_server/robotframework/parts/test_foldingrange.py b/tests/robotcode/language_server/robotframework/parts/test_foldingrange.py index 80a1ac5f..24018528 100644 --- a/tests/robotcode/language_server/robotframework/parts/test_foldingrange.py +++ b/tests/robotcode/language_server/robotframework/parts/test_foldingrange.py @@ -75,12 +75,13 @@ def test( result = [ r for r in result - if "start" in data.name.lower() - and r.start_line == data.line - or "end" in data.name.lower() - and r.end_line - == data.line - - (0 if ("else" in data.name.lower() or "if" in data.name.lower() or "for" in data.name.lower()) else 1) + if ("start" in data.name.lower() and r.start_line == data.line) + or ( + "end" in data.name.lower() + and r.end_line + == data.line + - (0 if ("else" in data.name.lower() or "if" in data.name.lower() or "for" in data.name.lower()) else 1) + ) ] assert result regtest.write(yaml.dump({"data": data, "result": result})) From 2f356d50c7f0eef95d704c7497e4c556448bd158 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 5 Dec 2024 17:08:32 +0100 Subject: [PATCH 11/13] style: some code formatting --- .../analyze/robot_framework_language_provider.py | 1 - packages/core/src/robotcode/core/ignore_spec.py | 1 - packages/core/src/robotcode/core/uri.py | 1 - packages/debugger/src/robotcode/debugger/run.py | 1 - packages/debugger/src/robotcode/debugger/server.py | 1 - .../language_server/common/parts/diagnostics.py | 5 ----- .../language_server/robotframework/parts/hover.py | 1 - .../language_server/robotframework/protocol.py | 1 - .../repl/src/robotcode/repl/console_interpreter.py | 2 -- packages/repl_server/src/robotcode/repl_server/cli.py | 1 - .../src/robotcode/repl_server/interpreter.py | 1 - packages/robot/src/robotcode/robot/config/loader.py | 1 - .../robot/diagnostics/diagnostics_modifier.py | 1 - .../src/robotcode/robot/diagnostics/imports_manager.py | 3 --- .../src/robotcode/robot/diagnostics/library_doc.py | 7 ------- .../robot/src/robotcode/robot/diagnostics/namespace.py | 6 ------ .../robotcode/robot/diagnostics/namespace_analyzer.py | 10 ---------- .../src/robotcode/runner/cli/discover/discover.py | 1 - packages/runner/src/robotcode/runner/cli/robot.py | 2 -- scripts/create_cmdline_doc.py | 2 -- tests/robotcode/robot/config/test_profile.py | 1 - 21 files changed, 50 deletions(-) diff --git a/packages/analyze/src/robotcode/analyze/robot_framework_language_provider.py b/packages/analyze/src/robotcode/analyze/robot_framework_language_provider.py index f870be8f..c38cf50b 100644 --- a/packages/analyze/src/robotcode/analyze/robot_framework_language_provider.py +++ b/packages/analyze/src/robotcode/analyze/robot_framework_language_provider.py @@ -68,7 +68,6 @@ def on_read_document_text(self, sender: Any, uri: Uri) -> str: return str(reader.read()) def collect_workspace_folder_files(self, folder: WorkspaceFolder) -> Iterable[Path]: - config = self.diagnostics_context.workspace.get_configuration(WorkspaceConfig, folder.uri) extensions = self.LANGUAGE_DEFINITION.extensions diff --git a/packages/core/src/robotcode/core/ignore_spec.py b/packages/core/src/robotcode/core/ignore_spec.py index de1ed1d3..82994139 100644 --- a/packages/core/src/robotcode/core/ignore_spec.py +++ b/packages/core/src/robotcode/core/ignore_spec.py @@ -142,7 +142,6 @@ def from_gitignore(cls, path: "os.PathLike[str]") -> "IgnoreSpec": def _rule_from_pattern( cls, pattern: str, base_path: PurePath, source: Optional[Tuple[str, int]] = None ) -> Optional[IgnoreRule]: - orig_pattern = pattern if pattern.strip() == "" or pattern[0] == "#": diff --git a/packages/core/src/robotcode/core/uri.py b/packages/core/src/robotcode/core/uri.py index 58e5e002..92713909 100644 --- a/packages/core/src/robotcode/core/uri.py +++ b/packages/core/src/robotcode/core/uri.py @@ -209,7 +209,6 @@ def change( query: Optional[str] = None, fragment: Optional[str] = None, ) -> Uri: - return Uri( scheme=scheme if scheme is not None else self.scheme, netloc=netloc if netloc is not None else self.netloc, diff --git a/packages/debugger/src/robotcode/debugger/run.py b/packages/debugger/src/robotcode/debugger/run.py index 88803011..11bb5795 100644 --- a/packages/debugger/src/robotcode/debugger/run.py +++ b/packages/debugger/src/robotcode/debugger/run.py @@ -52,7 +52,6 @@ def set_server(value: "DebugAdapterServer") -> None: @_logger.call def wait_for_server(timeout: float = 10) -> "DebugAdapterServer": - start_time = time.monotonic() while get_server() is None and time.monotonic() - start_time < timeout: time.sleep(0.005) diff --git a/packages/debugger/src/robotcode/debugger/server.py b/packages/debugger/src/robotcode/debugger/server.py index 58313387..5439b7d5 100644 --- a/packages/debugger/src/robotcode/debugger/server.py +++ b/packages/debugger/src/robotcode/debugger/server.py @@ -217,7 +217,6 @@ def initialized(self) -> None: @_logger.call def exit(self, exit_code: int) -> None: - with self._exited_lock: self.send_event(ExitedEvent(body=ExitedEventBody(exit_code=exit_code))) self._exited = True diff --git a/packages/language_server/src/robotcode/language_server/common/parts/diagnostics.py b/packages/language_server/src/robotcode/language_server/common/parts/diagnostics.py index 0d96402b..d12314eb 100644 --- a/packages/language_server/src/robotcode/language_server/common/parts/diagnostics.py +++ b/packages/language_server/src/robotcode/language_server/common/parts/diagnostics.py @@ -216,7 +216,6 @@ def _get_related_documents( check_current_task_canceled() if docs is not None: - if isinstance(docs, BaseException): if not isinstance(docs, CancelledError): self._logger.exception(docs, exc_info=result) @@ -340,7 +339,6 @@ def run_workspace_diagnostics(self) -> None: self.ensure_workspace_loaded() while True: - check_current_task_canceled() self.on_workspace_diagnostics_start(self) @@ -365,7 +363,6 @@ def run_workspace_diagnostics(self) -> None: context_name="workspace_diagnostics", level=logging.CRITICAL, ): - self.on_workspace_diagnostics_analyze(self) if self._break_diagnostics_loop_event.is_set(): @@ -558,9 +555,7 @@ def create_document_diagnostics_task( debounce: bool = True, send_diagnostics: bool = True, ) -> Task[Any]: - with self.get_diagnostics_data(document) as data: - if data.force or document.version != data.version or data.future is None or data.skipped_entries: future = data.future collect_slow = not data.single diff --git a/packages/language_server/src/robotcode/language_server/robotframework/parts/hover.py b/packages/language_server/src/robotcode/language_server/robotframework/parts/hover.py index 5facd3d3..ba742fac 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/parts/hover.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/parts/hover.py @@ -184,7 +184,6 @@ def _hover_default(self, nodes: List[ast.AST], document: TextDocument, position: ) if found_range is not None: - if kw.libtype == "RESOURCE": txt = kw.to_markdown( modify_doc_handler=lambda t: namespace.imports_manager.replace_variables_scalar( diff --git a/packages/language_server/src/robotcode/language_server/robotframework/protocol.py b/packages/language_server/src/robotcode/language_server/robotframework/protocol.py index d88b57d9..31f0391f 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/protocol.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/protocol.py @@ -215,7 +215,6 @@ def on_robot_initialized(sender) -> None: ... def server_initialized(self, sender: Any) -> None: for folder in self.workspace.workspace_folders: - for p in self.robot_profile.python_path or []: pa = Path(str(p)) if not pa.is_absolute(): diff --git a/packages/repl/src/robotcode/repl/console_interpreter.py b/packages/repl/src/robotcode/repl/console_interpreter.py index e735c409..0056e7a9 100644 --- a/packages/repl/src/robotcode/repl/console_interpreter.py +++ b/packages/repl/src/robotcode/repl/console_interpreter.py @@ -47,11 +47,9 @@ def get_input(self) -> Iterator[Optional[Keyword]]: for kw in test.body: yield kw else: - lines: List[str] = [] last_one = False while True: - prompt = "" if sys.stdin.isatty(): prompt = ">>> " if not lines else "... " diff --git a/packages/repl_server/src/robotcode/repl_server/cli.py b/packages/repl_server/src/robotcode/repl_server/cli.py index 085be778..3a3fe2d7 100644 --- a/packages/repl_server/src/robotcode/repl_server/cli.py +++ b/packages/repl_server/src/robotcode/repl_server/cli.py @@ -38,7 +38,6 @@ def set_server(value: Optional["ReplServer"]) -> None: def wait_for_server(task: "Task[Any]", timeout: float = 10) -> "ReplServer": - start_time = time.monotonic() while get_server() is None and time.monotonic() - start_time < timeout: time.sleep(0.005) diff --git a/packages/repl_server/src/robotcode/repl_server/interpreter.py b/packages/repl_server/src/robotcode/repl_server/interpreter.py index 26fe9231..2e1f40ca 100644 --- a/packages/repl_server/src/robotcode/repl_server/interpreter.py +++ b/packages/repl_server/src/robotcode/repl_server/interpreter.py @@ -290,7 +290,6 @@ def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None self._success = True if self._html_result is not None and isinstance(self._html_result, Element): - kw = self.create_keyword_html_element(result) old_children = next( diff --git a/packages/robot/src/robotcode/robot/config/loader.py b/packages/robot/src/robotcode/robot/config/loader.py index a81bda93..a937bec8 100644 --- a/packages/robot/src/robotcode/robot/config/loader.py +++ b/packages/robot/src/robotcode/robot/config/loader.py @@ -218,7 +218,6 @@ def find_project_root( root_folder: Optional[Path] = None, no_vcs: bool = False, ) -> Tuple[Optional[Path], DiscoverdBy]: - if root_folder: return root_folder.absolute(), DiscoverdBy.COMMAND_LINE diff --git a/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py b/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py index a48fc2b5..0f735f66 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py +++ b/packages/robot/src/robotcode/robot/diagnostics/diagnostics_modifier.py @@ -47,7 +47,6 @@ class RulesAndCodes: class ModifiersVisitor(Visitor): - def __init__(self) -> None: super().__init__() diff --git a/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py b/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py index e4b35298..3d8d0903 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py +++ b/packages/robot/src/robotcode/robot/diagnostics/imports_manager.py @@ -1089,7 +1089,6 @@ def _find_library_simple( name: str, base_dir: str, ) -> str: - if name in STDLIBS: result = ROBOT_LIBRARY_PACKAGE + "." + name else: @@ -1177,7 +1176,6 @@ def __find_variables_simple( name: str, base_dir: str, ) -> str: - if get_robot_version() >= (5, 0): if is_variables_by_path(name): return find_file_ex(name, base_dir, "Variables") @@ -1219,7 +1217,6 @@ def _get_library_libdoc( meta, _source, ignore_arguments = self.get_library_meta(name, base_dir, variables) if meta is not None and not meta.has_errors: - meta_file = meta.filepath_base + ".meta" if self.data_cache.cache_data_exists(CacheSection.LIBRARY, meta_file): try: diff --git a/packages/robot/src/robotcode/robot/diagnostics/library_doc.py b/packages/robot/src/robotcode/robot/diagnostics/library_doc.py index 4254c2a8..c8c9e285 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/library_doc.py +++ b/packages/robot/src/robotcode/robot/diagnostics/library_doc.py @@ -199,7 +199,6 @@ def convert_from_rest(text: str) -> str: if get_robot_version() >= (6, 0): - # monkey patch robot framework _old_from_name = EmbeddedArguments.from_name @@ -1515,7 +1514,6 @@ def report_invalid_syntax(self, message: str, level: str = "ERROR") -> None: def _get_default_variables() -> Any: - global __default_variables if __default_variables is None: __default_variables = Variables() @@ -1622,7 +1620,6 @@ def replace_variables_scalar( variables: Optional[Dict[str, Optional[Any]]] = None, ignore_errors: bool = False, ) -> Any: - _update_env(working_dir) if contains_variable(scalar, "$@&%"): @@ -1668,7 +1665,6 @@ def _find_library_internal( command_line_variables: Optional[Dict[str, Optional[Any]]] = None, variables: Optional[Dict[str, Optional[Any]]] = None, ) -> Tuple[str, Any]: - _update_env(working_dir) robot_variables = None @@ -1781,7 +1777,6 @@ def get_library_doc( command_line_variables: Optional[Dict[str, Optional[Any]]] = None, variables: Optional[Dict[str, Optional[Any]]] = None, ) -> LibraryDoc: - with _std_capture() as std_capturer: import_name, robot_variables = _find_library_internal( name, @@ -2147,7 +2142,6 @@ def _find_variables_internal( command_line_variables: Optional[Dict[str, Optional[Any]]] = None, variables: Optional[Dict[str, Optional[Any]]] = None, ) -> str: - _update_env(working_dir) if contains_variable(name, "$@&%"): @@ -2218,7 +2212,6 @@ def get_variables_doc( command_line_variables: Optional[Dict[str, Optional[Any]]] = None, variables: Optional[Dict[str, Optional[Any]]] = None, ) -> VariablesDoc: - import_name: str = name stem = Path(name).stem module_spec: Optional[ModuleSpec] = None diff --git a/packages/robot/src/robotcode/robot/diagnostics/namespace.py b/packages/robot/src/robotcode/robot/diagnostics/namespace.py index d4366f3d..65648f09 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/namespace.py +++ b/packages/robot/src/robotcode/robot/diagnostics/namespace.py @@ -169,7 +169,6 @@ def visit_Variable(self, node: Statement) -> None: # noqa: N802 class VariableVisitorBase(Visitor): - def __init__( self, namespace: "Namespace", @@ -320,7 +319,6 @@ def visit_KeywordName(self, node: Statement) -> None: # noqa: N802 class BlockVariableVisitor(OnlyArgumentsVisitor): - def visit_ExceptHeader(self, node: Statement) -> None: # noqa: N802 variables = node.get_tokens(Token.VARIABLE)[:1] if variables and is_scalar_assign(variables[0].value): @@ -1468,7 +1466,6 @@ def _import_imports( parent_import: Optional[Import] = None, parent_source: Optional[str] = None, ) -> Optional[Dict[str, Any]]: - with self._logger.measure_time( lambda: f"loading imports for {self.source if top_level else source}", context_name="import", @@ -1693,7 +1690,6 @@ def _import_lib(self, library: str, variables: Optional[Dict[str, Any]] = None) return None def _import_default_libraries(self, variables: Optional[Dict[str, Any]] = None) -> None: - with self._logger.measure_time(lambda: f"importing default libraries for {self.source}", context_name="import"): if variables is None: variables = self.get_suite_variables() @@ -1853,7 +1849,6 @@ def iter_all_keywords(self) -> Iterator[KeywordDoc]: def get_keywords(self) -> List[KeywordDoc]: with self._keywords_lock: if self._keywords is None: - i = 0 self.ensure_initialized() @@ -1880,7 +1875,6 @@ def append_diagnostics( related_information: Optional[List[DiagnosticRelatedInformation]] = None, data: Optional[Any] = None, ) -> None: - self._diagnostics.append( Diagnostic( range, diff --git a/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py b/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py index 630fc16f..81165544 100644 --- a/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py +++ b/packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py @@ -97,7 +97,6 @@ class AnalyzerResult: class NamespaceAnalyzer(Visitor): - _logger = LoggingDescriptor() def __init__( @@ -222,7 +221,6 @@ def _visit_Variable(self, node: Variable) -> None: # noqa: N802 add_to_references = True first_overidden_reference: Optional[VariableDefinition] = None if existing_var is not None: - self._variable_references[existing_var].add(Location(self._namespace.document_uri, r)) if existing_var not in self._overridden_variables: self._overridden_variables[existing_var] = var_def @@ -375,7 +373,6 @@ def _analyze_statement_variables( def _analyze_statement_expression_variables( self, node: Statement, severity: DiagnosticSeverity = DiagnosticSeverity.ERROR ) -> None: - for token in node.get_tokens(Token.ARGUMENT): self._analyze_token_variables(token, severity) self._analyze_token_expression_variables(token, severity) @@ -547,7 +544,6 @@ def _append_diagnostics( related_information: Optional[List[DiagnosticRelatedInformation]] = None, data: Optional[Any] = None, ) -> None: - self._diagnostics.append( Diagnostic( range, @@ -652,7 +648,6 @@ def _analyze_keyword_call( for d in self._finder.multiple_keywords_result: self._keyword_references[d].add(Location(self._namespace.document_uri, kw_range)) else: - self._keyword_references[result].add(Location(self._namespace.document_uri, kw_range)) if result.errors: @@ -1112,7 +1107,6 @@ def visit_KeywordName(self, node: KeywordName) -> None: # noqa: N802 name_token = node.get_token(Token.KEYWORD_NAME) if name_token is not None and name_token.value: - for variable_token in filter( lambda e: e.type == Token.VARIABLE, tokenize_variables(name_token, identifiers="$", ignore_errors=True), @@ -1470,7 +1464,6 @@ def visit_SectionHeader(self, node: Statement) -> None: # noqa: N802 if get_robot_version() >= (7, 0): def visit_ReturnSetting(self, node: Statement) -> None: # noqa: N802 - def _handler() -> None: self._analyze_statement_variables(node) @@ -1535,7 +1528,6 @@ def visit_VariablesImport(self, node: VariablesImport) -> None: # noqa: N802 break def visit_ResourceImport(self, node: ResourceImport) -> None: # noqa: N802 - if get_robot_version() >= (6, 1): self._check_import_name(node.name, node, "Resource") @@ -1647,7 +1639,6 @@ def _iter_variables_token( self, to: Token, ) -> Iterator[Tuple[Token, Optional[VariableDefinition]]]: - def exception_handler(e: BaseException, t: Token) -> None: self._append_diagnostics( range_from_token(t), @@ -1698,7 +1689,6 @@ def exception_handler(e: BaseException, t: Token) -> None: yield sub_token_or_var, var_def def _iter_variables_from_token(self, token: Token) -> Iterator[Tuple[Token, VariableDefinition]]: - if token.type == Token.VARIABLE and token.value.endswith("="): match = search_variable(token.value, ignore_errors=True) if not match.is_assign(allow_assign_mark=True): diff --git a/packages/runner/src/robotcode/runner/cli/discover/discover.py b/packages/runner/src/robotcode/runner/cli/discover/discover.py index 56fc6d5a..da2538d2 100644 --- a/packages/runner/src/robotcode/runner/cli/discover/discover.py +++ b/packages/runner/src/robotcode/runner/cli/discover/discover.py @@ -477,7 +477,6 @@ def handle_options( root_folder, profile, cmd_options = handle_robot_options(app, robot_options_and_args) with app.chdir(root_folder) as orig_folder: - diagnostics_logger = DiagnosticsLogger() try: _patch() diff --git a/packages/runner/src/robotcode/runner/cli/robot.py b/packages/runner/src/robotcode/runner/cli/robot.py index 29309a2e..caa7ce91 100644 --- a/packages/runner/src/robotcode/runner/cli/robot.py +++ b/packages/runner/src/robotcode/runner/cli/robot.py @@ -81,7 +81,6 @@ def _is_ignored(builder: SuiteStructureBuilder, path: Path) -> bool: curr_dir = Path(os.path.abspath(curr_dir)) if curr_dir not in cache_data.data: - parent_data: Optional[BuilderCacheData] = None parent_spec_dir: Optional[Path] = None @@ -242,7 +241,6 @@ def parse_arguments(self, cli_args: Any) -> Any: def handle_robot_options( app: Application, robot_options_and_args: Tuple[str, ...] ) -> Tuple[Optional[Path], RobotBaseProfile, List[str]]: - global _app _app = app diff --git a/scripts/create_cmdline_doc.py b/scripts/create_cmdline_doc.py index f5484049..38bf3f41 100644 --- a/scripts/create_cmdline_doc.py +++ b/scripts/create_cmdline_doc.py @@ -76,7 +76,6 @@ def generate(command: click.Command, depth: int = 2, parent_ctx: Optional[click. yield "" if isinstance(command, click.MultiCommand): - yield "**Commands:**" yield "" @@ -124,7 +123,6 @@ def generate(command: click.Command, depth: int = 2, parent_ctx: Optional[click. def main(): - cli_doc = Path("docs/03_reference/cli.md") regex = re.compile( diff --git a/tests/robotcode/robot/config/test_profile.py b/tests/robotcode/robot/config/test_profile.py index 926d3e2e..e92302df 100644 --- a/tests/robotcode/robot/config/test_profile.py +++ b/tests/robotcode/robot/config/test_profile.py @@ -368,7 +368,6 @@ def test_str_expression_works_correctly_in_lists_in_build_command_line() -> None def test_type_that_wants_alist_should_throw_an_error() -> None: - data = """\ [listeners] listener_with_colon = "dummy:output" From 639314b9e526e7e3d5820631db0c7c777ac9d648 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 5 Dec 2024 17:12:46 +0100 Subject: [PATCH 12/13] docs: update some docs --- docs/03_reference/cli.md | 180 +++++++++++++++--- .../src/robotcode/repl_server/cli.py | 2 +- 2 files changed, 154 insertions(+), 28 deletions(-) diff --git a/docs/03_reference/cli.md b/docs/03_reference/cli.md index 23ed777c..9763ae34 100644 --- a/docs/03_reference/cli.md +++ b/docs/03_reference/cli.md @@ -215,6 +215,10 @@ robotcode [OPTIONS] COMMAND [ARGS]... Run Robot Framework interactively. +- [`repl-server`](#repl-server) + + Start a REPL server, client can connect to the server and run the REPL scripts. + - [`robot`](#robot) Runs `robot` with the selected configuration, profiles, options and arguments. @@ -273,11 +277,10 @@ provided, the current directory is analyzed by default. The return code is a bitwise combination of the following values: -- `0`: **SUCCESS** - No issues detected. -- `1`: **ERRORS** - Critical issues found. -- `2`: **WARNINGS** - Non-critical issues detected. -- `4`: **INFORMATIONS** - General information messages. -- `8`: **HINTS** - Suggestions or improvements. +- `0`: **SUCCESS** - No issues detected. - `1`: **ERRORS** - Critical issues +found. - `2`: **WARNINGS** - Non-critical issues detected. - `4`: +**INFORMATIONS** - General information messages. - `8`: **HINTS** - +Suggestions or improvements. *Examples*: ``` @@ -303,7 +306,7 @@ robotcode analyze code [OPTIONS] [PATHS]... - `-f, --filter PATTERN *` - Glob pattern to filter files to analyze. Can be specified multiple times. + Glob pattern to filter files to analyze. Can be specified multiple times. - `-v, --variable name:value *` @@ -653,17 +656,17 @@ robotcode debug [OPTIONS] [ROBOT_OPTIONS_AND_ARGS]... - `--tcp [
:]` - Run in `tcp` server mode and listen at the given port. (Equivalent to `--mode tcp --port `) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe-name, port, mode. + Run in `tcp` server mode and listen at the given port. (Equivalent to `--mode tcp --port `) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe-name, mode, port. - `--pipe-server NAME` - Run in `pipe-server` mode and listen at the given pipe name. (Equivalent to `--mode pipe-server --pipe-name `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, mode, bind, tcp. + Run in `pipe-server` mode and listen at the given pipe name. (Equivalent to `--mode pipe-server --pipe-name `) *NOTE:* This option is mutually exclusive with options: port, tcp, bind, pipe-name, mode. -- `--mode [tcp|pipe-server]` +- `--mode [pipe-server|tcp]` - The mode to use for the debug launch server. *NOTE:* This option is mutually exclusive with options: tcp, pipe-server. [env var: ROBOTCODE_MODE; default: tcp] + The mode to use for the debug launch server. *NOTE:* This option is mutually exclusive with options: pipe-server, tcp. [env var: ROBOTCODE_MODE; default: tcp] - `--port PORT` @@ -678,7 +681,7 @@ robotcode debug [OPTIONS] [ROBOT_OPTIONS_AND_ARGS]... - `--pipe-name NAME` - The pipe to listen on or connect to. (Only valid in `pipe` and `pipe-server` mode) *NOTE:* This option is mutually exclusive with options: tcp, pipe-server, port, bind. [env var: ROBOTCODE_PIPE_NAME] + The pipe to listen on or connect to. (Only valid in `pipe` and `pipe-server` mode) *NOTE:* This option is mutually exclusive with options: pipe-server, tcp, bind, port. [env var: ROBOTCODE_PIPE_NAME] - `--version` @@ -705,47 +708,47 @@ robotcode debug-launch [OPTIONS] **Options:** - `--stdio` - Run in `stdio` mode. (Equivalent to `--mode stdio`) *NOTE:* This option is mutually exclusive with options: pipe-name, port, socket, pipe-server, mode, bind, tcp, pipe. [env var: ROBOTCODE_STDIO] + Run in `stdio` mode. (Equivalent to `--mode stdio`) *NOTE:* This option is mutually exclusive with options: socket, port, pipe, pipe-server, tcp, bind, pipe-name, mode. [env var: ROBOTCODE_STDIO] - `--tcp [
:]` - Run in `tcp` server mode and listen at the given port. (Equivalent to `--mode tcp --port `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, socket, pipe-server, mode, stdio, pipe. + Run in `tcp` server mode and listen at the given port. (Equivalent to `--mode tcp --port `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, pipe-server, pipe-name, mode. - `--socket [
:]` - Run in `socket` mode and connect to the given port. (Equivalent to `--mode socket --port `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, pipe-server, mode, tcp, stdio, pipe. + Run in `socket` mode and connect to the given port. (Equivalent to `--mode socket --port `) *NOTE:* This option is mutually exclusive with options: stdio, port, pipe, pipe-server, tcp, pipe-name, mode. - `--pipe NAME` - Run in `pipe` mode and connect to the given pipe name. (Equivalent to `--mode pipe --pipe-name `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, socket, pipe-server, mode, bind, tcp, stdio. + Run in `pipe` mode and connect to the given pipe name. (Equivalent to `--mode pipe --pipe-name `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe-server, tcp, bind, pipe-name, mode. - `--pipe-server NAME` - Run in `pipe-server` mode and listen at the given pipe name. (Equivalent to `--mode pipe-server --pipe-name `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, socket, mode, bind, tcp, stdio, pipe. + Run in `pipe-server` mode and listen at the given pipe name. (Equivalent to `--mode pipe-server --pipe-name `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, tcp, bind, pipe-name, mode. - `--mode [stdio|tcp|socket|pipe|pipe-server]` - The mode to use for the debug launch server. *NOTE:* This option is mutually exclusive with options: socket, pipe-server, tcp, stdio, pipe. [env var: ROBOTCODE_MODE; default: stdio] + The mode to use for the debug launch server. *NOTE:* This option is mutually exclusive with options: stdio, socket, pipe, pipe-server, tcp. [env var: ROBOTCODE_MODE; default: stdio] - `--port PORT` - The port to listen on or connect to. (Only valid for `tcp` and `socket mode`) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe, pipe-name. [env var: ROBOTCODE_PORT; default: 6611; 1<=x<=65535] + The port to listen on or connect to. (Only valid for `tcp` and `socket mode`) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe-name, pipe. [env var: ROBOTCODE_PORT; default: 6611; 1<=x<=65535] - `--bind ADDRESS *` - Specify alternate bind address. If no address is specified `localhost` is used. (Only valid for tcp and socket mode) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe, pipe-name. [env var: ROBOTCODE_BIND; default: 127.0.0.1] + Specify alternate bind address. If no address is specified `localhost` is used. (Only valid for tcp and socket mode) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe-name, pipe. [env var: ROBOTCODE_BIND; default: 127.0.0.1] - `--pipe-name NAME` - The pipe to listen on or connect to. (Only valid in `pipe` and `pipe-server` mode) *NOTE:* This option is mutually exclusive with options: port, socket, pipe-server, bind, tcp, stdio, pipe. [env var: ROBOTCODE_PIPE_NAME] + The pipe to listen on or connect to. (Only valid in `pipe` and `pipe-server` mode) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, pipe-server, tcp, bind. [env var: ROBOTCODE_PIPE_NAME] - `--version` @@ -1175,27 +1178,27 @@ robotcode language-server [OPTIONS] [PATHS]... **Options:** - `--stdio` - Run in `stdio` mode. (Equivalent to `--mode stdio`) *NOTE:* This option is mutually exclusive with options: pipe-name, port, socket, mode, bind, tcp, pipe. [env var: ROBOTCODE_STDIO] + Run in `stdio` mode. (Equivalent to `--mode stdio`) *NOTE:* This option is mutually exclusive with options: socket, port, pipe, tcp, bind, pipe-name, mode. [env var: ROBOTCODE_STDIO] - `--tcp [
:]` - Run in `tcp` server mode and listen at the given port. (Equivalent to `--mode tcp --port `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, socket, mode, stdio, pipe. + Run in `tcp` server mode and listen at the given port. (Equivalent to `--mode tcp --port `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, pipe-name, mode. - `--socket [
:]` - Run in `socket` mode and connect to the given port. (Equivalent to `--mode socket --port `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, mode, tcp, stdio, pipe. + Run in `socket` mode and connect to the given port. (Equivalent to `--mode socket --port `) *NOTE:* This option is mutually exclusive with options: stdio, port, pipe, tcp, pipe-name, mode. - `--pipe NAME` - Run in `pipe` mode and connect to the given pipe name. (Equivalent to `--mode pipe --pipe-name `) *NOTE:* This option is mutually exclusive with options: pipe-name, port, socket, mode, bind, tcp, stdio. + Run in `pipe` mode and connect to the given pipe name. (Equivalent to `--mode pipe --pipe-name `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, tcp, bind, pipe-name, mode. -- `--mode [socket|stdio|pipe|tcp]` +- `--mode [stdio|tcp|socket|pipe]` - The mode to use for the debug launch server. *NOTE:* This option is mutually exclusive with options: socket, stdio, tcp, pipe. [env var: ROBOTCODE_MODE; default: stdio] + The mode to use for the debug launch server. *NOTE:* This option is mutually exclusive with options: stdio, tcp, socket, pipe. [env var: ROBOTCODE_MODE; default: stdio] - `--port PORT` @@ -1210,7 +1213,7 @@ robotcode language-server [OPTIONS] [PATHS]... - `--pipe-name NAME` - The pipe to listen on or connect to. (Only valid in `pipe` and `pipe-server` mode) *NOTE:* This option is mutually exclusive with options: port, socket, bind, tcp, stdio, pipe. [env var: ROBOTCODE_PIPE_NAME] + The pipe to listen on or connect to. (Only valid in `pipe` and `pipe-server` mode) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, tcp, bind. [env var: ROBOTCODE_PIPE_NAME] - `--version` @@ -1441,6 +1444,129 @@ robotcode repl [OPTIONS] [FILES]... xUnit output file. see `robot --xunit` option. +- `-s, --source FILE` + + Specifies the path to a source file. This file must not exist and will neither be read nor written. It is used solely to set the current working directory for the REPL script and to assign a name to the internal suite. + + +- `--version` + + Show the version and exit. + + +- `--help` + + Show this message and exit. + + +#### repl-server + +Start a REPL server, client can connect to the server and run the REPL +scripts. + + +**Usage:** +```text +robotcode repl-server [OPTIONS] [FILES]... +``` + + +**Options:** +- `--stdio` + + Run in `stdio` mode. (Equivalent to `--mode stdio`) *NOTE:* This option is mutually exclusive with options: socket, port, pipe, pipe-server, tcp, bind, pipe-name, mode. [env var: ROBOTCODE_STDIO] + + +- `--tcp [
:]` + + Run in `tcp` server mode and listen at the given port. (Equivalent to `--mode tcp --port `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, pipe-server, pipe-name, mode. + + +- `--socket [
:]` + + Run in `socket` mode and connect to the given port. (Equivalent to `--mode socket --port `) *NOTE:* This option is mutually exclusive with options: stdio, port, pipe, pipe-server, tcp, pipe-name, mode. + + +- `--pipe NAME` + + Run in `pipe` mode and connect to the given pipe name. (Equivalent to `--mode pipe --pipe-name `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe-server, tcp, bind, pipe-name, mode. + + +- `--pipe-server NAME` + + Run in `pipe-server` mode and listen at the given pipe name. (Equivalent to `--mode pipe-server --pipe-name `) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, tcp, bind, pipe-name, mode. + + +- `--mode [stdio|tcp|socket|pipe|pipe-server]` + + The mode to use for the debug launch server. *NOTE:* This option is mutually exclusive with options: stdio, socket, pipe, pipe-server, tcp. [env var: ROBOTCODE_MODE; default: stdio] + + +- `--port PORT` + + The port to listen on or connect to. (Only valid for `tcp` and `socket mode`) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe-name, pipe. [env var: ROBOTCODE_PORT; default: 6601; 1<=x<=65535] + + +- `--bind ADDRESS *` + + Specify alternate bind address. If no address is specified `localhost` is used. (Only valid for tcp and socket mode) *NOTE:* This option is mutually exclusive with options: pipe-server, pipe-name, pipe. [env var: ROBOTCODE_BIND; default: 127.0.0.1] + + +- `--pipe-name NAME` + + The pipe to listen on or connect to. (Only valid in `pipe` and `pipe-server` mode) *NOTE:* This option is mutually exclusive with options: stdio, socket, port, pipe, pipe-server, tcp, bind. [env var: ROBOTCODE_PIPE_NAME] + + +- `-v, --variable name:value *` + + Set variables in the test data. see `robot --variable` option. + + +- `-V, --variablefile PATH *` + + Python or YAML file file to read variables from. see `robot --variablefile` option. + + +- `-P, --pythonpath PATH *` + + Additional locations where to search test libraries and other extensions when they are imported. see `robot --pythonpath` option. + + +- `-d, --outputdir DIR` + + Where to create output files. see `robot --outputdir` option. + + +- `-o, --output FILE` + + XML output file. see `robot --output` option. + + +- `-r, --report FILE` + + HTML output file. see `robot --report` option. + + +- `-l, --log FILE` + + HTML log file. see `robot --log` option. + + +- `-x, --xunit FILE` + + xUnit output file. see `robot --xunit` option. + + +- `--version` + + Show the version and exit. + + +- `-s, --source FILE` + + Specifies the path to a source file. This file must not exist and will neither be read nor written. It is used solely to set the current working directory for the REPL script and to assign a name to the internal suite. + + - `--help` Show this message and exit. diff --git a/packages/repl_server/src/robotcode/repl_server/cli.py b/packages/repl_server/src/robotcode/repl_server/cli.py index 3a3fe2d7..1781878a 100644 --- a/packages/repl_server/src/robotcode/repl_server/cli.py +++ b/packages/repl_server/src/robotcode/repl_server/cli.py @@ -190,7 +190,7 @@ def repl_server( files: Tuple[Path, ...], ) -> None: """\ - Run Robot Framework interactively. + Start a REPL server, client can connect to the server and run the REPL scripts. """ mode, port, bind, pipe_name = resolve_server_options( From fcf3cf3d0ab49e79e16d76bcbc6fee07a12c72d0 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Thu, 5 Dec 2024 17:16:23 +0100 Subject: [PATCH 13/13] =?UTF-8?q?chore(release):=20bump=20version=200.99.0?= =?UTF-8?q?=20=E2=86=92=200.100.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 30 ++++++++++++++++--- package-lock.json | 4 +-- package.json | 4 +-- packages/analyze/pyproject.toml | 6 ++-- .../src/robotcode/analyze/__version__.py | 2 +- .../core/src/robotcode/core/__version__.py | 2 +- packages/debugger/pyproject.toml | 4 +-- .../src/robotcode/debugger/__version__.py | 2 +- packages/jsonrpc2/pyproject.toml | 2 +- .../src/robotcode/jsonrpc2/__version__.py | 2 +- packages/language_server/pyproject.toml | 8 ++--- .../robotcode/language_server/__version__.py | 2 +- .../src/robotcode/modifiers/__version__.py | 2 +- .../src/robotcode/plugin/__version__.py | 2 +- packages/repl/pyproject.toml | 2 +- .../repl/src/robotcode/repl/__version__.py | 2 +- packages/repl_server/pyproject.toml | 4 +-- .../src/robotcode/repl_server/__version__.py | 2 +- packages/robot/pyproject.toml | 2 +- .../robot/src/robotcode/robot/__version__.py | 2 +- packages/runner/pyproject.toml | 8 ++--- .../src/robotcode/runner/__version__.py | 2 +- pyproject.toml | 30 +++++++++---------- src/robotcode/cli/__version__.py | 2 +- 24 files changed, 75 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2cb4fa4..3bd7d787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines. +## [0.100.0](https://github.com/robotcodedev/robotcode/compare/v0.99.0..v0.100.0) - 2024-12-05 + +### Bug Fixes + +- **analyze:** Corrected statistics about analyzed files ([18b6cb8](https://github.com/robotcodedev/robotcode/commit/18b6cb878e893b32ce26b16c3de0c6e628367fde)) +- **analyzer:** Correct handling of variables in embedded args in keyword calls ([2c8ed56](https://github.com/robotcodedev/robotcode/commit/2c8ed5662be1e8621d7d9c742275ccaf1809d06c)) +- **config:** Corrected handling of relative items in python path and other variables if current folder is different then root folder of the project ([66a94bc](https://github.com/robotcodedev/robotcode/commit/66a94bc993a27d8fe5cec13813e524b1099509c6)) +- **vscode:** Corrected highlightning of bold/italic in documentation tags ([170287d](https://github.com/robotcodedev/robotcode/commit/170287db04ec811e39b7ec5e7bd853ae9d98ec7c)) + + +### Documentation + +- Update some docs ([639314b](https://github.com/robotcodedev/robotcode/commit/639314b9e526e7e3d5820631db0c7c777ac9d648)) + + +### Features + +- **analyzer:** Add error codes `VariableNotReplaced` and `EnvironmentVariableNotReplaced` for variables not found/replaced in documentation, tags, and metadata ([c5f766f](https://github.com/robotcodedev/robotcode/commit/c5f766f036e49153f318e91ddefb68c975668669)) +- **vscode:** Added some better file icons ([39fad12](https://github.com/robotcodedev/robotcode/commit/39fad12e6cc8d1246dc45c8e843fa1c3b046a491)) +- **vscode:** Preview of Robot Framework Notebook support for VSCode ([9185ccd](https://github.com/robotcodedev/robotcode/commit/9185ccd84dbb9f2f5cd2aba4212598abd93ef0f1)) + + ## [0.99.0](https://github.com/robotcodedev/robotcode/compare/v0.98.0..v0.99.0) - 2024-11-20 ### Bug Fixes @@ -14,10 +36,10 @@ All notable changes to this project will be documented in this file. See [conven - **analyze:** `analyze code` now return a flag that indicates if errors/warnings/etc. occurs ([5125f7d](https://github.com/robotcodedev/robotcode/commit/5125f7dca21daf18f21708ab0676d8707fbb2827)) - `0`: **SUCCESS** - No issues detected. - - `1`: **ERRORS** - Critical issues found. - - `2`: **WARNINGS** - Non-critical issues detected. - - `4`: **INFORMATIONS** - General information messages. - - `8`: **HINTS** - Suggestions or improvements. + - `1`: **ERRORS** - Critical issues found. + - `2`: **WARNINGS** - Non-critical issues detected. + - `4`: **INFORMATIONS** - General information messages. + - `8`: **HINTS** - Suggestions or improvements. A return code 1 means error and 3 means there are errors and warning and so on. diff --git a/package-lock.json b/package-lock.json index a7d7cb78..e5c27640 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "robotcode", - "version": "0.99.0", + "version": "0.100.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "robotcode", - "version": "0.99.0", + "version": "0.100.0", "funding": [ { "type": "opencollective", diff --git a/package.json b/package.json index 54a085da..a737cc21 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Robot Framework IntelliSense, linting, test execution and debugging, code formatting, refactoring, and many more", "icon": "images/icon.png", "publisher": "d-biehl", - "version": "0.99.0", + "version": "0.100.0", "author": { "name": "Daniel Biehl", "url": "https://github.com/robotcodedev/" @@ -1926,4 +1926,4 @@ "workspaces": [ "docs" ] -} \ No newline at end of file +} diff --git a/packages/analyze/pyproject.toml b/packages/analyze/pyproject.toml index bd3974a7..97a19825 100644 --- a/packages/analyze/pyproject.toml +++ b/packages/analyze/pyproject.toml @@ -27,9 +27,9 @@ classifiers = [ ] dependencies = [ "robotframework>=4.1.0", - "robotcode-plugin==0.99.0", - "robotcode-robot==0.99.0", - "robotcode==0.99.0", + "robotcode-plugin==0.100.0", + "robotcode-robot==0.100.0", + "robotcode==0.100.0", ] dynamic = ["version"] diff --git a/packages/analyze/src/robotcode/analyze/__version__.py b/packages/analyze/src/robotcode/analyze/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/analyze/src/robotcode/analyze/__version__.py +++ b/packages/analyze/src/robotcode/analyze/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/core/src/robotcode/core/__version__.py b/packages/core/src/robotcode/core/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/core/src/robotcode/core/__version__.py +++ b/packages/core/src/robotcode/core/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/debugger/pyproject.toml b/packages/debugger/pyproject.toml index 97646d63..1cbd2d82 100644 --- a/packages/debugger/pyproject.toml +++ b/packages/debugger/pyproject.toml @@ -28,8 +28,8 @@ classifiers = [ dynamic = ["version"] dependencies = [ "robotframework>=4.1.0", - "robotcode-jsonrpc2==0.99.0", - "robotcode-runner==0.99.0", + "robotcode-jsonrpc2==0.100.0", + "robotcode-runner==0.100.0", ] [project.optional-dependencies] diff --git a/packages/debugger/src/robotcode/debugger/__version__.py b/packages/debugger/src/robotcode/debugger/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/debugger/src/robotcode/debugger/__version__.py +++ b/packages/debugger/src/robotcode/debugger/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/jsonrpc2/pyproject.toml b/packages/jsonrpc2/pyproject.toml index 0c2f8c0e..63f1e9c6 100644 --- a/packages/jsonrpc2/pyproject.toml +++ b/packages/jsonrpc2/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ "Framework :: Robot Framework", "Framework :: Robot Framework :: Tool", ] -dependencies = ["robotcode-core==0.99.0"] +dependencies = ["robotcode-core==0.100.0"] dynamic = ["version"] [project.urls] diff --git a/packages/jsonrpc2/src/robotcode/jsonrpc2/__version__.py b/packages/jsonrpc2/src/robotcode/jsonrpc2/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/jsonrpc2/src/robotcode/jsonrpc2/__version__.py +++ b/packages/jsonrpc2/src/robotcode/jsonrpc2/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/language_server/pyproject.toml b/packages/language_server/pyproject.toml index c19b292e..5286d484 100644 --- a/packages/language_server/pyproject.toml +++ b/packages/language_server/pyproject.toml @@ -27,10 +27,10 @@ classifiers = [ ] dependencies = [ "robotframework>=4.1.0", - "robotcode-jsonrpc2==0.99.0", - "robotcode-robot==0.99.0", - "robotcode-analyze==0.99.0", - "robotcode==0.99.0", + "robotcode-jsonrpc2==0.100.0", + "robotcode-robot==0.100.0", + "robotcode-analyze==0.100.0", + "robotcode==0.100.0", ] dynamic = ["version"] diff --git a/packages/language_server/src/robotcode/language_server/__version__.py b/packages/language_server/src/robotcode/language_server/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/language_server/src/robotcode/language_server/__version__.py +++ b/packages/language_server/src/robotcode/language_server/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/modifiers/src/robotcode/modifiers/__version__.py b/packages/modifiers/src/robotcode/modifiers/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/modifiers/src/robotcode/modifiers/__version__.py +++ b/packages/modifiers/src/robotcode/modifiers/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/plugin/src/robotcode/plugin/__version__.py b/packages/plugin/src/robotcode/plugin/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/plugin/src/robotcode/plugin/__version__.py +++ b/packages/plugin/src/robotcode/plugin/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/repl/pyproject.toml b/packages/repl/pyproject.toml index 3c803265..1319eddd 100644 --- a/packages/repl/pyproject.toml +++ b/packages/repl/pyproject.toml @@ -27,7 +27,7 @@ classifiers = [ ] dynamic = ["version"] dependencies = [ - "robotcode-runner==0.99.0" + "robotcode-runner==0.100.0" ] [project.entry-points.robotcode] diff --git a/packages/repl/src/robotcode/repl/__version__.py b/packages/repl/src/robotcode/repl/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/repl/src/robotcode/repl/__version__.py +++ b/packages/repl/src/robotcode/repl/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/repl_server/pyproject.toml b/packages/repl_server/pyproject.toml index e6b37d4a..8a8f7fa9 100644 --- a/packages/repl_server/pyproject.toml +++ b/packages/repl_server/pyproject.toml @@ -27,8 +27,8 @@ classifiers = [ ] dynamic = ["version"] dependencies = [ - "robotcode-jsonrpc2==0.99.0", - "robotcode-runner==0.99.0" + "robotcode-jsonrpc2==0.100.0", + "robotcode-runner==0.100.0" ] [project.entry-points.robotcode] diff --git a/packages/repl_server/src/robotcode/repl_server/__version__.py b/packages/repl_server/src/robotcode/repl_server/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/repl_server/src/robotcode/repl_server/__version__.py +++ b/packages/repl_server/src/robotcode/repl_server/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/robot/pyproject.toml b/packages/robot/pyproject.toml index 939576fe..83eb3121 100644 --- a/packages/robot/pyproject.toml +++ b/packages/robot/pyproject.toml @@ -30,7 +30,7 @@ dependencies = [ "robotframework>=4.1.0", "tomli>=1.1.0; python_version < '3.11'", "platformdirs>=3.2.0,<4.4.0", - "robotcode-core==0.99.0", + "robotcode-core==0.100.0", ] dynamic = ["version"] diff --git a/packages/robot/src/robotcode/robot/__version__.py b/packages/robot/src/robotcode/robot/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/robot/src/robotcode/robot/__version__.py +++ b/packages/robot/src/robotcode/robot/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/packages/runner/pyproject.toml b/packages/runner/pyproject.toml index e35d1d05..60f9f813 100644 --- a/packages/runner/pyproject.toml +++ b/packages/runner/pyproject.toml @@ -28,10 +28,10 @@ classifiers = [ dynamic = ["version"] dependencies = [ "robotframework>=4.1.0", - "robotcode-robot==0.99.0", - "robotcode-modifiers==0.99.0", - "robotcode-plugin==0.99.0", - "robotcode==0.99.0", + "robotcode-robot==0.100.0", + "robotcode-modifiers==0.100.0", + "robotcode-plugin==0.100.0", + "robotcode==0.100.0", ] [project.entry-points.robotcode] diff --git a/packages/runner/src/robotcode/runner/__version__.py b/packages/runner/src/robotcode/runner/__version__.py index c0f51b71..a366a2a7 100644 --- a/packages/runner/src/robotcode/runner/__version__.py +++ b/packages/runner/src/robotcode/runner/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0" diff --git a/pyproject.toml b/pyproject.toml index 540fe879..6751ce4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,9 +51,9 @@ classifiers = [ ] requires-python = ">=3.8" dependencies = [ - "robotcode-core==0.99.0", - "robotcode-plugin==0.99.0", - "robotcode-robot==0.99.0", + "robotcode-core==0.100.0", + "robotcode-plugin==0.100.0", + "robotcode-robot==0.100.0", ] dynamic = ["version"] @@ -71,24 +71,24 @@ robotcode = "robotcode.cli.__main__:main" [project.optional-dependencies] -debugger = ["robotcode-debugger==0.99.0"] -languageserver = ["robotcode-language-server==0.99.0"] -runner = ["robotcode-runner==0.99.0"] -analyze = ["robotcode-analyze==0.99.0"] +debugger = ["robotcode-debugger==0.100.0"] +languageserver = ["robotcode-language-server==0.100.0"] +runner = ["robotcode-runner==0.100.0"] +analyze = ["robotcode-analyze==0.100.0"] yaml = ["PyYAML>=5.4"] lint = ["robotframework-robocop>=2.0.0"] tidy = ["robotframework-tidy>=2.0.0"] rest = ["docutils"] -repl = ["robotcode-repl==0.99.0"] -replserver = ["robotcode-repl-server==0.99.0"] +repl = ["robotcode-repl==0.100.0"] +replserver = ["robotcode-repl-server==0.100.0"] colored = ["rich"] all = [ - "robotcode-debugger==0.99.0", - "robotcode-language-server==0.99.0", - "robotcode-runner==0.99.0", - "robotcode-analyze==0.99.0", - "robotcode-repl==0.99.0", - "robotcode-repl-server==0.99.0", + "robotcode-debugger==0.100.0", + "robotcode-language-server==0.100.0", + "robotcode-runner==0.100.0", + "robotcode-analyze==0.100.0", + "robotcode-repl==0.100.0", + "robotcode-repl-server==0.100.0", "PyYAML>=5.4", "robotframework-robocop>=2.0.0", "robotframework-tidy>=2.0.0", diff --git a/src/robotcode/cli/__version__.py b/src/robotcode/cli/__version__.py index c0f51b71..a366a2a7 100644 --- a/src/robotcode/cli/__version__.py +++ b/src/robotcode/cli/__version__.py @@ -1 +1 @@ -__version__ = "0.99.0" +__version__ = "0.100.0"