From 3392ebcc4feba726e067e2a4b74ebda2efd06663 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 7 Oct 2023 19:22:46 +0100 Subject: [PATCH 01/50] Update CHANGES.rst --- lib/pytest-lsp/CHANGES.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pytest-lsp/CHANGES.rst b/lib/pytest-lsp/CHANGES.rst index 4989cab..91cef4c 100644 --- a/lib/pytest-lsp/CHANGES.rst +++ b/lib/pytest-lsp/CHANGES.rst @@ -1,6 +1,11 @@ v0.3.1 - 2023-10-06 ------------------- +This release includes some minor breaking changes if you were using the lower-level APIs e.g ``make_client_server``. + +See `this commit `__ for a sample migration + + Enhancements ^^^^^^^^^^^^ From aadcf9c65c06ba495802cca8525ebace966d844a Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 9 Oct 2023 18:59:17 +0100 Subject: [PATCH 02/50] Remove proof of concept web app Since the agent was refactored to use TCP I doubt it works now anyway and it's probably easier to maintain a textual app rather than a web one. The code can easily be recovered via the `app` tag if we decide to resurrect/reference it one day --- README.md | 7 - app/index.html | 64 - app/package-lock.json | 3849 ---------------------------------------- app/package.json | 26 - app/src/index.ts | 87 - app/styles.css | 3 - app/tailwind.config.js | 14 - app/tsconfig.json | 16 - app/webpack.config.js | 26 - 9 files changed, 4092 deletions(-) delete mode 100644 app/index.html delete mode 100644 app/package-lock.json delete mode 100644 app/package.json delete mode 100644 app/src/index.ts delete mode 100644 app/styles.css delete mode 100644 app/tailwind.config.js delete mode 100644 app/tsconfig.json delete mode 100644 app/webpack.config.js diff --git a/README.md b/README.md index 2149210..675b35b 100644 --- a/README.md +++ b/README.md @@ -80,10 +80,3 @@ async def test_completion(client: LanguageClient): assert len(result.items) > 0 ``` - -## `app/` - Prototype Devtools Web UI - -![UI Screenshot](https://user-images.githubusercontent.com/2675694/191863035-5bb5d1c9-00b6-40de-b3e2-f81cdb9eb375.png) - -This is little more than a proof of concept, currently setup to communicate with an agent over websockets. -Hopefully, this can eventually be repurposed/extended to be used on lsp servers hosted entirely in the browser e.g. pyodide. diff --git a/app/index.html b/app/index.html deleted file mode 100644 index 0b85390..0000000 --- a/app/index.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - LSP Devtools - - - - - - -
-
- - - - - - - - - - - - - - -
TimestampSourceIDMethodParamsResultError
-
-
- -
-
- - - - - - - - diff --git a/app/package-lock.json b/app/package-lock.json deleted file mode 100644 index 8da5187..0000000 --- a/app/package-lock.json +++ /dev/null @@ -1,3849 +0,0 @@ -{ - "name": "lsp-devtools", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "lsp-devtools", - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "vanilla-jsoneditor": "^0.7.5", - "vscode-jsonrpc": "^8.0.2", - "vscode-ws-jsonrpc": "^2.0.0" - }, - "devDependencies": { - "@tailwindcss/forms": "^0.5.3", - "@tailwindcss/typography": "^0.5.7", - "tailwindcss": "^3.1.8", - "ts-loader": "^9.4.1", - "typescript": "^4.8.3", - "webpack": "^5.74.0", - "webpack-cli": "^4.10.0" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", - "dev": true, - "dependencies": { - "mini-svg-data-uri": "^1.2.3" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" - } - }, - "node_modules/@tailwindcss/typography": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.7.tgz", - "integrity": "sha512-JTTSTrgZfp6Ki4svhPA4mkd9nmQ/j9EfE7SbHJ1cLtthKkpW2OxsFXzSmxbhYbEkfNIyAyhle5p4SYyKRbz/jg==", - "dev": true, - "dependencies": { - "lodash.castarray": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "postcss-selector-parser": "6.0.10" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/@types/eslint": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", - "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.7.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", - "dev": true, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", - "dev": true, - "dependencies": { - "envinfo": "^7.7.3" - }, - "peerDependencies": { - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", - "dev": true, - "peerDependencies": { - "webpack-cli": "4.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001409", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz", - "integrity": "sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==", - "dev": true - }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.4.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", - "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==", - "dev": true - }, - "node_modules/enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.castarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", - "dev": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true, - "bin": { - "mini-svg-data-uri": "cli.js" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", - "dev": true, - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.6" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.8.tgz", - "integrity": "sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==", - "dev": true, - "dependencies": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "detective": "^5.2.1", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "lilconfig": "^2.0.6", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.14", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.10", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", - "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.14", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser/node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-loader": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", - "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/vanilla-jsoneditor": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/vanilla-jsoneditor/-/vanilla-jsoneditor-0.7.5.tgz", - "integrity": "sha512-15WEA//oMRPKCfmKK/TDBZVrjlywElxhiZEJf3W1wLU2XjrlvG/GEbhreNAbhjkoH6oO5uDvzcNatj2WZkxy3g==" - }, - "node_modules/vscode-jsonrpc": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", - "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-ws-jsonrpc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vscode-ws-jsonrpc/-/vscode-ws-jsonrpc-2.0.0.tgz", - "integrity": "sha512-FgTx05ARqmh2gy9k/e4imvr+7wVSXzd8AXE/Rd9d/eDXQwJPbaa7w+PLiswo3MX5FY0Ujk143w2ezELN/Dp14Q==", - "dependencies": { - "vscode-jsonrpc": "^8.0.2" - }, - "engines": { - "node": ">=16.11.0", - "npm": ">=8.0.0" - } - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack": { - "version": "5.74.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", - "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "cross-spawn": "^7.0.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "@webpack-cli/migrate": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/webpack/node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - } - }, - "dependencies": { - "@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", - "dev": true, - "requires": { - "mini-svg-data-uri": "^1.2.3" - } - }, - "@tailwindcss/typography": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.7.tgz", - "integrity": "sha512-JTTSTrgZfp6Ki4svhPA4mkd9nmQ/j9EfE7SbHJ1cLtthKkpW2OxsFXzSmxbhYbEkfNIyAyhle5p4SYyKRbz/jg==", - "dev": true, - "requires": { - "lodash.castarray": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "postcss-selector-parser": "6.0.10" - } - }, - "@types/eslint": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", - "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "@types/node": { - "version": "18.7.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", - "dev": true, - "requires": {} - }, - "@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", - "dev": true, - "requires": { - "envinfo": "^7.7.3" - } - }, - "@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", - "dev": true, - "requires": {} - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001409", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz", - "integrity": "sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==", - "dev": true - }, - "detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "requires": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - } - }, - "didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.4.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", - "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==", - "dev": true - }, - "enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true - }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true - }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", - "dev": true - }, - "loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash.castarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", - "dev": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", - "dev": true, - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - } - }, - "postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.6" - } - }, - "postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "requires": { - "pify": "^2.3.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "requires": { - "resolve": "^1.9.0" - } - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "tailwindcss": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.8.tgz", - "integrity": "sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==", - "dev": true, - "requires": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "detective": "^5.2.1", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "lilconfig": "^2.0.6", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.14", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.10", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1" - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "terser": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz", - "integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.14", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "ts-loader": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", - "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - } - }, - "typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "vanilla-jsoneditor": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/vanilla-jsoneditor/-/vanilla-jsoneditor-0.7.5.tgz", - "integrity": "sha512-15WEA//oMRPKCfmKK/TDBZVrjlywElxhiZEJf3W1wLU2XjrlvG/GEbhreNAbhjkoH6oO5uDvzcNatj2WZkxy3g==" - }, - "vscode-jsonrpc": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", - "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==" - }, - "vscode-ws-jsonrpc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vscode-ws-jsonrpc/-/vscode-ws-jsonrpc-2.0.0.tgz", - "integrity": "sha512-FgTx05ARqmh2gy9k/e4imvr+7wVSXzd8AXE/Rd9d/eDXQwJPbaa7w+PLiswo3MX5FY0Ujk143w2ezELN/Dp14Q==", - "requires": { - "vscode-jsonrpc": "^8.0.2" - } - }, - "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "webpack": { - "version": "5.74.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", - "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} - } - } - }, - "webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", - "dev": true, - "requires": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "cross-spawn": "^7.0.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - } - } - }, - "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - } - } -} diff --git a/app/package.json b/app/package.json deleted file mode 100644 index fda2276..0000000 --- a/app/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "lsp-devtools", - "version": "0.1.0", - "description": "Developer tooling for language servers", - "main": "index.js", - "scripts": { - "dev": "npx webpack --mode development && npx tailwindcss -i styles.css -o dist/styles.css", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "MIT", - "devDependencies": { - "@tailwindcss/forms": "^0.5.3", - "@tailwindcss/typography": "^0.5.7", - "tailwindcss": "^3.1.8", - "ts-loader": "^9.4.1", - "typescript": "^4.8.3", - "webpack": "^5.74.0", - "webpack-cli": "^4.10.0" - }, - "dependencies": { - "vanilla-jsoneditor": "^0.7.5", - "vscode-jsonrpc": "^8.0.2", - "vscode-ws-jsonrpc": "^2.0.0" - } -} diff --git a/app/src/index.ts b/app/src/index.ts deleted file mode 100644 index 96de0a9..0000000 --- a/app/src/index.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { JSONEditor } from "vanilla-jsoneditor"; -import * as rpc from 'vscode-ws-jsonrpc' - - -const tableBody = document.getElementById('table-body') -const tableRowTemplate: HTMLTemplateElement = document.getElementById('table-row') -const viewButtonTemplate: HTMLTemplateElement = document.getElementById('view-button') - -const jsonViewer = new JSONEditor({ - target: document.getElementById('json-viewer'), - props: { - // readOnly: true - } -}) - -/** - * Represents a LSP protocol message, as captured by the agent. - */ -interface LSPMessage { - session: string, - timestamp: number, - source: string, - id?: string, - method?: string, - params?: any, - result?: any, - error?: any, -} - - -function addRow(message: LSPMessage) { - const rowContainer = tableRowTemplate.content.cloneNode(true) - let cells = rowContainer.querySelectorAll('td') - - let ts = new Date(message.timestamp * 1000) - - cells[0].textContent = `${ts.toLocaleTimeString()}.${ts.getMilliseconds()}` - cells[1].textContent = `${message.source}` - cells[2].textContent = message.id ? `${message.id}` : '' - cells[3].textContent = message.method ? `${message.method}` : '' - - if (message.params) { - const fragment = viewButtonTemplate.content.cloneNode(true) - const button = fragment.querySelector('button') - - button.addEventListener('click', (event) => { - jsonViewer.set({ json: message.params }) - }) - - cells[4].appendChild(button) - } - - if (message.result) { - const fragment = viewButtonTemplate.content.cloneNode(true) - const button = fragment.querySelector('button') - - button.addEventListener('click', (event) => { - jsonViewer.set({ json: message.result }) - }) - - cells[5].appendChild(button) - } - - if (message.error) { - const fragment = viewButtonTemplate.content.cloneNode(true) - const button = fragment.querySelector('button') - - button.addEventListener('click', (event) => { - jsonViewer.set({ json: message.error }) - }) - - cells[6].appendChild(button) - } - - tableBody?.appendChild(rowContainer) -} - -rpc.listen({ - webSocket: new WebSocket('ws://localhost:8765'), - onConnection: (connection: rpc.MessageConnection) => { - let notification = new rpc.NotificationType('$/lspMessage') - connection.onNotification(notification, (params: LSPMessage) => { - addRow(params) - }) - connection.listen() - } -}) diff --git a/app/styles.css b/app/styles.css deleted file mode 100644 index b5c61c9..0000000 --- a/app/styles.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/app/tailwind.config.js b/app/tailwind.config.js deleted file mode 100644 index 7a10797..0000000 --- a/app/tailwind.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: [ - './index.html', - './src/**/*.ts' - ], - plugins: [ - require('@tailwindcss/forms'), - require('@tailwindcss/typography') - ], - theme: { - extend: {}, - }, -} diff --git a/app/tsconfig.json b/app/tsconfig.json deleted file mode 100644 index ce27f73..0000000 --- a/app/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "include": [ - "src" - ], - "compilerOptions": { - "outDir": "dist", - "module": "commonjs", - "moduleResolution": "node", - "lib": [ - "ES2019", - "DOM" - ], - "strict": true, - "sourceMap": true - } -} diff --git a/app/webpack.config.js b/app/webpack.config.js deleted file mode 100644 index 9ea2154..0000000 --- a/app/webpack.config.js +++ /dev/null @@ -1,26 +0,0 @@ -const path = require('path') - -module.exports = { - target: 'web', - entry: './src/index.ts', - output: { - path: path.resolve(__dirname, 'dist'), - filename: 'index.js', - }, - devtool: 'source-map', - resolve: { - extensions: ['.ts', '.js'], - mainFields: ['module', 'main'] - }, - module: { - rules: [ - { - test: /.ts$/, - exclude: /node_modules/, - use: [{ - loader: 'ts-loader', - }] - } - ] - } -} From 1f4ad978d3933e03fcc510bc4eacb658d21ed437 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 18:02:28 +0000 Subject: [PATCH 03/50] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c5c5f50..0fc0f53 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ exclude: '.bumpversion.cfg$' repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-yaml - id: end-of-file-fixer From e5337065f89f84a45dc798ab4ee6666191be5cd7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 18:03:13 +0000 Subject: [PATCH 04/50] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- lib/lsp-devtools/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lsp-devtools/README.md b/lib/lsp-devtools/README.md index a2af2a5..56edc7c 100644 --- a/lib/lsp-devtools/README.md +++ b/lib/lsp-devtools/README.md @@ -5,7 +5,7 @@ While this is a Python package, it can be used with language servers written in ![lsp-devtools client](https://user-images.githubusercontent.com/2675694/273293510-e43fdc92-03dd-40c9-aaca-ddb5e526031a.png) -Available commands: +Available commands: - `agent`: Wraps a language server, allows the other commands to access the messages sent between client and server. - `client`: **Experimental** a language client with an embedded inspector. Powered by [textual](https://textual.textualize.io/) From d3a1c4da377a7c50e5efdbd2b93f39f02dd92269 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:50:21 +0000 Subject: [PATCH 05/50] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.5.1 → v1.6.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.5.1...v1.6.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0fc0f53..9265d8b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: exclude: 'lib/pytest-lsp/pytest_lsp/gen.py' - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.5.1' + rev: 'v1.6.0' hooks: - id: mypy name: mypy (pytest-lsp) From 38a1ad1672b0cbc31ea6971f8284b675500db009 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 18 Oct 2023 21:54:31 +0100 Subject: [PATCH 06/50] vscode: Add sphinx-build command --- .vscode/settings.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a6c128d..76af123 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,5 +21,12 @@ "**/*.egg-info": true, "**/.pytest_cache": true, "**/.mypy_cache": true, - } + }, + "esbonio.sphinx.buildCommand": [ + "sphinx-build", + "-M", + "html", + "docs", + "docs/_build" + ], } From fce681d2288c81c403f87c48aaf22330d13eb9c0 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 18 Oct 2023 22:01:48 +0100 Subject: [PATCH 07/50] pytest-lsp: Capture `clientInfo` as well as capabilities --- lib/pytest-lsp/pytest_lsp/client.py | 3 +- .../pytest_lsp/clients/neovim_v0.6.1.json | 420 ++++++----- .../clients/visual_studio_code_v1.65.2.json | 706 +++++++++--------- lib/pytest-lsp/tests/test_client.py | 3 +- 4 files changed, 572 insertions(+), 560 deletions(-) diff --git a/lib/pytest-lsp/pytest_lsp/client.py b/lib/pytest-lsp/pytest_lsp/client.py index 98e6d65..ba279e1 100644 --- a/lib/pytest-lsp/pytest_lsp/client.py +++ b/lib/pytest-lsp/pytest_lsp/client.py @@ -234,4 +234,5 @@ def client_capabilities(client_spec: str) -> types.ClientCapabilities: converter = get_converter() capabilities = json.loads(filename.read_text()) - return converter.structure(capabilities, types.ClientCapabilities) + params = converter.structure(capabilities, types.InitializeParams) + return params.capabilities diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json index 7446789..61c79b2 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json @@ -1,225 +1,231 @@ { - "workspace": { - "applyEdit": true, - "workspaceEdit": { - "resourceOperations": [ - "rename", - "create", - "delete" - ] - }, - "symbol": { - "dynamicRegistration": false, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] - } - }, - "workspaceFolders": true, - "configuration": true + "clientInfo": { + "name": "Neovim", + "version": "0.6.1" }, - "textDocument": { - "synchronization": { - "dynamicRegistration": false, - "willSave": false, - "willSaveWaitUntil": false, - "didSave": true - }, - "completion": { - "dynamicRegistration": false, - "completionItem": { - "snippetSupport": false, - "commitCharactersSupport": false, - "documentationFormat": [ - "markdown", - "plaintext" - ], - "deprecatedSupport": false, - "preselectSupport": false - }, - "completionItemKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25 + "capabilities": { + "workspace": { + "applyEdit": true, + "workspaceEdit": { + "resourceOperations": [ + "rename", + "create", + "delete" ] }, - "contextSupport": false - }, - "hover": { - "dynamicRegistration": false, - "contentFormat": [ - "markdown", - "plaintext" - ] - }, - "signatureHelp": { - "dynamicRegistration": false, - "signatureInformation": { - "documentationFormat": [ + "symbol": { + "dynamicRegistration": false, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + } + }, + "workspaceFolders": true, + "configuration": true + }, + "textDocument": { + "synchronization": { + "dynamicRegistration": false, + "willSave": false, + "willSaveWaitUntil": false, + "didSave": true + }, + "completion": { + "dynamicRegistration": false, + "completionItem": { + "snippetSupport": false, + "commitCharactersSupport": false, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "deprecatedSupport": false, + "preselectSupport": false + }, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + }, + "contextSupport": false + }, + "hover": { + "dynamicRegistration": false, + "contentFormat": [ "markdown", "plaintext" - ], - "parameterInformation": { - "labelOffsetSupport": true - }, - "activeParameterSupport": true - } - }, - "declaration": { - "linkSupport": true - }, - "definition": { - "linkSupport": true - }, - "typeDefinition": { - "linkSupport": true - }, - "implementation": { - "linkSupport": true - }, - "references": { - "dynamicRegistration": false - }, - "documentHighlight": { - "dynamicRegistration": false - }, - "documentSymbol": { - "dynamicRegistration": false, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 ] }, - "hierarchicalDocumentSymbolSupport": true - }, - "codeAction": { - "dynamicRegistration": false, - "codeActionLiteralSupport": { - "codeActionKind": { + "signatureHelp": { + "dynamicRegistration": false, + "signatureInformation": { + "documentationFormat": [ + "markdown", + "plaintext" + ], + "parameterInformation": { + "labelOffsetSupport": true + }, + "activeParameterSupport": true + } + }, + "declaration": { + "linkSupport": true + }, + "definition": { + "linkSupport": true + }, + "typeDefinition": { + "linkSupport": true + }, + "implementation": { + "linkSupport": true + }, + "references": { + "dynamicRegistration": false + }, + "documentHighlight": { + "dynamicRegistration": false + }, + "documentSymbol": { + "dynamicRegistration": false, + "symbolKind": { "valueSet": [ - "", - "Empty", - "QuickFix", - "Refactor", - "RefactorExtract", - "RefactorInline", - "RefactorRewrite", - "Source", - "SourceOrganizeImports", - "quickfix", - "refactor", - "refactor.extract", - "refactor.inline", - "refactor.rewrite", - "source", - "source.organizeImports" + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "hierarchicalDocumentSymbolSupport": true + }, + "codeAction": { + "dynamicRegistration": false, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "Empty", + "QuickFix", + "Refactor", + "RefactorExtract", + "RefactorInline", + "RefactorRewrite", + "Source", + "SourceOrganizeImports", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + }, + "dataSupport": true, + "resolveSupport": { + "properties": [ + "edit" ] } }, - "dataSupport": true, - "resolveSupport": { - "properties": [ - "edit" - ] + "rename": { + "dynamicRegistration": false, + "prepareSupport": true + }, + "publishDiagnostics": { + "relatedInformation": true, + "tagSupport": { + "valueSet": [ + 1, + 2 + ] + } } }, - "rename": { - "dynamicRegistration": false, - "prepareSupport": true - }, - "publishDiagnostics": { - "relatedInformation": true, - "tagSupport": { - "valueSet": [ - 1, - 2 - ] - } - } - }, - "window": { - "workDoneProgress": true, - "showMessage": { - "messageActionItem": { - "additionalPropertiesSupport": false + "window": { + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": false + } + }, + "showDocument": { + "support": false } - }, - "showDocument": { - "support": false } } } diff --git a/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json b/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json index 3f5e5ae..9c09b2b 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json +++ b/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json @@ -1,383 +1,389 @@ { - "workspace": { - "applyEdit": true, - "workspaceEdit": { - "documentChanges": true, - "resourceOperations": [ - "create", - "rename", - "delete" - ], - "failureHandling": "textOnlyTransactional", - "normalizesLineEndings": true, - "changeAnnotationSupport": { - "groupsOnLabel": true - } - }, - "didChangeConfiguration": { - "dynamicRegistration": true - }, - "didChangeWatchedFiles": { - "dynamicRegistration": true - }, - "symbol": { - "dynamicRegistration": true, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] + "clientInfo": { + "name": "Visual Studio Code", + "version": "1.65.2" + }, + "capabilities": { + "workspace": { + "applyEdit": true, + "workspaceEdit": { + "documentChanges": true, + "resourceOperations": [ + "create", + "rename", + "delete" + ], + "failureHandling": "textOnlyTransactional", + "normalizesLineEndings": true, + "changeAnnotationSupport": { + "groupsOnLabel": true + } }, - "tagSupport": { - "valueSet": [ - 1 - ] + "didChangeConfiguration": { + "dynamicRegistration": true + }, + "didChangeWatchedFiles": { + "dynamicRegistration": true + }, + "symbol": { + "dynamicRegistration": true, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "tagSupport": { + "valueSet": [ + 1 + ] + } + }, + "executeCommand": { + "dynamicRegistration": true + }, + "workspaceFolders": true, + "configuration": true, + "semanticTokens": { + "refreshSupport": true + }, + "codeLens": { + "refreshSupport": true + }, + "fileOperations": { + "dynamicRegistration": true, + "didCreate": true, + "willCreate": true, + "didRename": true, + "willRename": true, + "didDelete": true, + "willDelete": true } }, - "executeCommand": { - "dynamicRegistration": true - }, - "workspaceFolders": true, - "configuration": true, - "semanticTokens": { - "refreshSupport": true - }, - "codeLens": { - "refreshSupport": true - }, - "fileOperations": { - "dynamicRegistration": true, - "didCreate": true, - "willCreate": true, - "didRename": true, - "willRename": true, - "didDelete": true, - "willDelete": true - } - }, - "textDocument": { - "synchronization": { - "dynamicRegistration": true, - "willSave": true, - "willSaveWaitUntil": true, - "didSave": true - }, - "completion": { - "dynamicRegistration": true, - "completionItem": { - "snippetSupport": true, - "commitCharactersSupport": true, - "documentationFormat": [ + "textDocument": { + "synchronization": { + "dynamicRegistration": true, + "willSave": true, + "willSaveWaitUntil": true, + "didSave": true + }, + "completion": { + "dynamicRegistration": true, + "completionItem": { + "snippetSupport": true, + "commitCharactersSupport": true, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "deprecatedSupport": true, + "preselectSupport": true, + "tagSupport": { + "valueSet": [ + 1 + ] + }, + "insertReplaceSupport": true, + "resolveSupport": { + "properties": [ + "documentation", + "detail", + "additionalTextEdits" + ] + }, + "insertTextModeSupport": { + "valueSet": [ + 1, + 2 + ] + } + }, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + }, + "contextSupport": true + }, + "hover": { + "dynamicRegistration": true, + "contentFormat": [ "markdown", "plaintext" - ], - "deprecatedSupport": true, - "preselectSupport": true, + ] + }, + "signatureHelp": { + "dynamicRegistration": true, + "signatureInformation": { + "documentationFormat": [ + "markdown", + "plaintext" + ], + "parameterInformation": { + "labelOffsetSupport": true + }, + "activeParameterSupport": true + }, + "contextSupport": true + }, + "declaration": { + "dynamicRegistration": true, + "linkSupport": true + }, + "definition": { + "dynamicRegistration": true, + "linkSupport": true + }, + "typeDefinition": { + "dynamicRegistration": true, + "linkSupport": true + }, + "implementation": { + "dynamicRegistration": true, + "linkSupport": true + }, + "references": { + "dynamicRegistration": true + }, + "documentHighlight": { + "dynamicRegistration": true + }, + "documentSymbol": { + "dynamicRegistration": true, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "hierarchicalDocumentSymbolSupport": true, "tagSupport": { "valueSet": [ 1 ] }, - "insertReplaceSupport": true, + "labelSupport": true + }, + "codeAction": { + "dynamicRegistration": true, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + }, + "isPreferredSupport": true, + "disabledSupport": true, + "dataSupport": true, "resolveSupport": { "properties": [ - "documentation", - "detail", - "additionalTextEdits" + "edit" ] }, - "insertTextModeSupport": { - "valueSet": [ - 1, - 2 - ] - } + "honorsChangeAnnotations": false }, - "completionItemKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25 - ] + "codeLens": { + "dynamicRegistration": true }, - "contextSupport": true - }, - "hover": { - "dynamicRegistration": true, - "contentFormat": [ - "markdown", - "plaintext" - ] - }, - "signatureHelp": { - "dynamicRegistration": true, - "signatureInformation": { - "documentationFormat": [ - "markdown", - "plaintext" - ], - "parameterInformation": { - "labelOffsetSupport": true - }, - "activeParameterSupport": true + "documentLink": { + "dynamicRegistration": true, + "tooltipSupport": true }, - "contextSupport": true - }, - "declaration": { - "dynamicRegistration": true, - "linkSupport": true - }, - "definition": { - "dynamicRegistration": true, - "linkSupport": true - }, - "typeDefinition": { - "dynamicRegistration": true, - "linkSupport": true - }, - "implementation": { - "dynamicRegistration": true, - "linkSupport": true - }, - "references": { - "dynamicRegistration": true - }, - "documentHighlight": { - "dynamicRegistration": true - }, - "documentSymbol": { - "dynamicRegistration": true, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] + "colorProvider": { + "dynamicRegistration": true }, - "hierarchicalDocumentSymbolSupport": true, - "tagSupport": { - "valueSet": [ - 1 - ] + "formatting": { + "dynamicRegistration": true }, - "labelSupport": true - }, - "codeAction": { - "dynamicRegistration": true, - "codeActionLiteralSupport": { - "codeActionKind": { + "rangeFormatting": { + "dynamicRegistration": true + }, + "onTypeFormatting": { + "dynamicRegistration": true + }, + "rename": { + "dynamicRegistration": true, + "prepareSupport": true, + "prepareSupportDefaultBehavior": 1, + "honorsChangeAnnotations": true + }, + "publishDiagnostics": { + "relatedInformation": true, + "tagSupport": { "valueSet": [ - "", - "quickfix", - "refactor", - "refactor.extract", - "refactor.inline", - "refactor.rewrite", - "source", - "source.organizeImports" + 1, + 2 ] - } + }, + "versionSupport": false, + "codeDescriptionSupport": true, + "dataSupport": true }, - "isPreferredSupport": true, - "disabledSupport": true, - "dataSupport": true, - "resolveSupport": { - "properties": [ - "edit" - ] + "foldingRange": { + "dynamicRegistration": true, + "rangeLimit": 5000, + "lineFoldingOnly": true }, - "honorsChangeAnnotations": false - }, - "codeLens": { - "dynamicRegistration": true - }, - "documentLink": { - "dynamicRegistration": true, - "tooltipSupport": true - }, - "colorProvider": { - "dynamicRegistration": true - }, - "formatting": { - "dynamicRegistration": true - }, - "rangeFormatting": { - "dynamicRegistration": true - }, - "onTypeFormatting": { - "dynamicRegistration": true - }, - "rename": { - "dynamicRegistration": true, - "prepareSupport": true, - "prepareSupportDefaultBehavior": 1, - "honorsChangeAnnotations": true - }, - "publishDiagnostics": { - "relatedInformation": true, - "tagSupport": { - "valueSet": [ - 1, - 2 - ] + "selectionRange": { + "dynamicRegistration": true }, - "versionSupport": false, - "codeDescriptionSupport": true, - "dataSupport": true - }, - "foldingRange": { - "dynamicRegistration": true, - "rangeLimit": 5000, - "lineFoldingOnly": true - }, - "selectionRange": { - "dynamicRegistration": true - }, - "linkedEditingRange": { - "dynamicRegistration": true - }, - "callHierarchy": { - "dynamicRegistration": true + "linkedEditingRange": { + "dynamicRegistration": true + }, + "callHierarchy": { + "dynamicRegistration": true + }, + "semanticTokens": { + "requests": { + "range": true, + "full": { + "delta": true + } + }, + "tokenTypes": [ + "namespace", + "type", + "class", + "enum", + "interface", + "struct", + "typeParameter", + "parameter", + "variable", + "property", + "enumMember", + "event", + "function", + "method", + "macro", + "keyword", + "modifier", + "comment", + "string", + "number", + "regexp", + "operator" + ], + "tokenModifiers": [ + "declaration", + "definition", + "readonly", + "static", + "deprecated", + "abstract", + "async", + "modification", + "documentation", + "defaultLibrary" + ], + "formats": [ + "relative" + ], + "overlappingTokenSupport": false, + "multilineTokenSupport": false, + "dynamicRegistration": true + } }, - "semanticTokens": { - "requests": { - "range": true, - "full": { - "delta": true + "window": { + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": true } }, - "tokenTypes": [ - "namespace", - "type", - "class", - "enum", - "interface", - "struct", - "typeParameter", - "parameter", - "variable", - "property", - "enumMember", - "event", - "function", - "method", - "macro", - "keyword", - "modifier", - "comment", - "string", - "number", - "regexp", - "operator" - ], - "tokenModifiers": [ - "declaration", - "definition", - "readonly", - "static", - "deprecated", - "abstract", - "async", - "modification", - "documentation", - "defaultLibrary" - ], - "formats": [ - "relative" - ], - "overlappingTokenSupport": false, - "multilineTokenSupport": false, - "dynamicRegistration": true - } - }, - "window": { - "workDoneProgress": true, - "showMessage": { - "messageActionItem": { - "additionalPropertiesSupport": true + "showDocument": { + "support": true } }, - "showDocument": { - "support": true - } - }, - "general": { - "regularExpressions": { - "engine": "ECMAScript", - "version": "ES2020" - }, - "markdown": { - "parser": "marked", - "version": "1.1.0" + "general": { + "regularExpressions": { + "engine": "ECMAScript", + "version": "ES2020" + }, + "markdown": { + "parser": "marked", + "version": "1.1.0" + } } } } diff --git a/lib/pytest-lsp/tests/test_client.py b/lib/pytest-lsp/tests/test_client.py index 102bc7f..388a031 100644 --- a/lib/pytest-lsp/tests/test_client.py +++ b/lib/pytest-lsp/tests/test_client.py @@ -5,7 +5,6 @@ import pygls.uris as uri import pytest - import pytest_lsp @@ -32,7 +31,7 @@ def test_client_capabilities( clients_dir = pathlib.Path(pytest_lsp.__file__).parent / "clients" with (clients_dir / client_capabilities).open() as f: # Easiest way to reformat the JSON onto a single line - expected = json.dumps(json.load(f)) + expected = json.dumps(json.load(f)["capabilities"]) pytester.makeini( """ From ee97af4287a4e26e4f8603ca66ba9dc668e9ea78 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 18 Oct 2023 22:05:31 +0100 Subject: [PATCH 08/50] docs: Add capabilities extension This extension will provide directives for constructing tables showcasing which versions of which clients support a given capability. There's a long way to go as only `bool` attributes and a single version of a client are currently supported. --- docs/conf.py | 4 + docs/ext/capabilities.py | 238 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 docs/ext/capabilities.py diff --git a/docs/conf.py b/docs/conf.py index 538e610..7a91042 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,11 +24,15 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ + # built-in extensions "sphinx.ext.autodoc", "sphinx.ext.napoleon", "sphinx.ext.intersphinx", + # 3rd party extensions "sphinx_copybutton", "sphinx_design", + # local extensions + "capabilities", "supported_clients", ] diff --git a/docs/ext/capabilities.py b/docs/ext/capabilities.py new file mode 100644 index 0000000..b0df22c --- /dev/null +++ b/docs/ext/capabilities.py @@ -0,0 +1,238 @@ +import importlib.resources as resources +import json +import pathlib +import re +import typing +from typing import List + +import attrs +from docutils import nodes +from docutils.parsers.rst import directives +from lsprotocol import types +from lsprotocol.converters import get_converter +from pygls.capabilities import get_capability +from sphinx.application import Sphinx +from sphinx.domains import Domain +from sphinx.pycode import ModuleAnalyzer +from sphinx.util.docutils import SphinxDirective + + +class BoolTable(SphinxDirective): + """Given a boolean capability, indicate the support across known clients and + versions""" + + required_arguments = 1 + + option_spec = { + "caption": directives.unchanged, + } + + def build_header(self): + columns = ["Client", "Supported Since"] + colspecs = [nodes.colspec("", colwidth="1") for _ in range(len(columns))] + header = nodes.thead( + "", + nodes.row("", *[nodes.entry("", nodes.Text(col)) for col in columns]), + ) + + return header, colspecs + + def build_body(self, capability: str): + rows = [] + domain = self.env.domains["capabilities"] + + for (name, version), capabilities in domain.clients.items(): + supported = get_capability(capabilities, capability, False) + rows.append( + nodes.row( + "", + nodes.entry("", nodes.Text(name)), + nodes.entry( + "", + nodes.Text(version if supported else " - "), + classes=["centered"], + ), + ) + ) + + return nodes.tbody("", *rows) + + def run(self): + domain = self.env.domains["capabilities"] + + capability = self.arguments[0] + if len(documentation := domain.get_capability_documentation(capability)) > 0: + self.state_machine.insert_input(documentation, "") + + header, colspecs = self.build_header() + body = self.build_body(capability) + + table = nodes.table("", nodes.tgroup("", *colspecs, header, body)) + + if (caption := self.options.get("caption", None)) is not None: + table.insert(0, nodes.title("", caption)) + + paragraph = nodes.paragraph( + "", + nodes.Text("Capability: "), + nodes.literal("", to_camel_case(capability)), + ) + + return [table, paragraph] + + +def to_camel_case(snake_text: str) -> str: + """Convert snake_case to camelCase""" + first, *remaining = snake_text.split("_") + return first + "".join([text[0].upper() + text[1:] for text in remaining]) + + +def _load_clients(): + """Load client capability data from pytest_lsp""" + clients = {} + converter = get_converter() + + for resource in resources.files("pytest_lsp.clients").iterdir(): + if not resource.name.endswith(".json"): + continue + + capabilities = json.loads(pathlib.Path(resource).read_text()) + params = converter.structure(capabilities, types.InitializeParams) + + name = params.client_info.name + version = params.client_info.version + + clients[(name, version)] = params.capabilities + + return clients + + +CODE_FENCE_PATTERN = re.compile(r"```(\w+)?") +LINK_PATTERN = re.compile(r"\{@link ([^}]+)\}") +LITERAL_PATTERN = re.compile(r"(?`` with ``**LSP v**`` + + - Replaces ``{@link }`` with ``:class:`~lsprotocol.types.` `` + + - Replaces markdown hyperlink with reStructuredText equivalent + + - Replaces inline markdown code (single "`") with reStructuredText inline code + (double "`") + + - Inserts the required newline before a bulleted list + + - Replaces code fences with code blocks + + - Fixes indentation + """ + + line_breaks = [] + code_fences = [] + + for i, line in enumerate(lines): + if line.startswith("- "): + line_breaks.append(i) + + # Does the line need dedenting? + if line.startswith(" " * 4) and not lines[i - 1].startswith(" "): + # Be sure to modify the original list *and* the line the rest of the + # loop will use. + line = lines[i][4:] + lines[i] = line + + if (match := SINCE_PATTERN.search(line)) is not None: + start, end = match.span() + lines[i] = "".join([line[:start], f"**LSP v{match.group(1)}**", line[end:]]) + + if (match := LINK_PATTERN.search(line)) is not None: + start, end = match.span() + item = match.group(1) + + lines[i] = "".join( + [line[:start], f":class:`~pygls:lsprotocol.types.{item}`", line[end:]] + ) + + if (match := MD_LINK_PATTERN.search(line)) is not None: + start, end = match.span() + text = match.group(1) + target = match.group(2) + + line = "".join([line[:start], f"`{text} <{target}>`__", line[end:]]) + lines[i] = line + + if (match := LITERAL_PATTERN.search(line)) is not None: + start, end = match.span() + lines[i] = "".join([line[:start], f"`{match.group(0)}` ", line[end:]]) + + if (match := CODE_FENCE_PATTERN.match(line)) is not None: + open_ = len(code_fences) % 2 == 0 + lang = match.group(1) or "" + + if open_: + code_fences.append((i, lang)) + line_breaks.extend([i, i + 1]) + else: + code_fences.append(i) + + # Rewrite fenced code blocks + open_ = -1 + for fence in code_fences: + if isinstance(fence, tuple): + open_ = fence[0] + 1 + lines[fence[0]] = f".. code-block:: {fence[1]}" + else: + # Indent content + for j in range(open_, fence): + lines[j] = f" {lines[j]}" + + lines[fence] = "" + + # Insert extra line breaks + for offset, line in enumerate(line_breaks): + lines.insert(line + offset, "") + + +class CapabilitiesDomain(Domain): + name = "capabilities" + + directives = { + "bool-table": BoolTable, + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.clients = _load_clients() + self.analyzer = ModuleAnalyzer.for_module("lsprotocol.types") + self.analyzer.analyze() + + def get_capability_documentation(self, field_name: str) -> List[str]: + """Return the documentation associated with the given capability.""" + type_ = types.ClientCapabilities + parent = type_.__name__ + + *parents, field = field_name.split(".") + for p in parents: + attr = attrs.fields_dict(type_)[p] + + type_ = attr.type + if len(args := typing.get_args(type_)) > 0: + type_ = args[0] + + parent = type_.__name__ + + lines = self.analyzer.attr_docs.get((parent, field), []) + process_docstring(lines) + + return lines + + +def setup(app: Sphinx): + app.add_domain(CapabilitiesDomain) From c5551f622ca82c4ac7e85030b9aeefde25c0ce87 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 18 Oct 2023 22:11:40 +0100 Subject: [PATCH 09/50] docs: Add client capability index --- docs/capabilities/text-document.rst | 8 +++ .../text-document/code-action.rst | 29 ++++++++++ docs/capabilities/text-document/code-lens.rst | 9 +++ .../capabilities/text-document/completion.rst | 40 +++++++++++++ .../text-document/declaration.rst | 14 +++++ .../capabilities/text-document/definition.rst | 14 +++++ .../capabilities/text-document/diagnostic.rst | 14 +++++ .../text-document/document-color.rst | 9 +++ .../text-document/document-highlight.rst | 9 +++ .../text-document/document-link.rst | 14 +++++ .../text-document/document-symbols.rst | 19 +++++++ .../text-document/folding-range.rst | 14 +++++ .../capabilities/text-document/formatting.rst | 9 +++ docs/capabilities/text-document/hover.rst | 9 +++ .../text-document/implementation.rst | 14 +++++ .../capabilities/text-document/inlay-hint.rst | 9 +++ .../text-document/inline-value.rst | 9 +++ .../text-document/linked-editing-range.rst | 9 +++ docs/capabilities/text-document/moniker.rst | 9 +++ .../text-document/on-type-formatting.rst | 9 +++ .../text-document/preapare-call-hierachy.rst | 9 +++ .../text-document/preapare-type-hierachy.rst | 9 +++ .../text-document/publish-diagnostics.rst | 24 ++++++++ .../text-document/range-formatting.rst | 9 +++ .../capabilities/text-document/references.rst | 9 +++ docs/capabilities/text-document/rename.rst | 19 +++++++ .../text-document/selection-range.rst | 9 +++ .../text-document/semantic-tokens.rst | 45 +++++++++++++++ .../text-document/signature-help.rst | 24 ++++++++ .../text-document/type-definition.rst | 14 +++++ docs/capabilities/window.rst | 8 +++ docs/capabilities/window/progress.rst | 4 ++ docs/capabilities/window/show-document.rst | 6 ++ docs/capabilities/window/show-message.rst | 9 +++ docs/capabilities/workspace.rst | 8 +++ docs/capabilities/workspace/apply-edit.rst | 6 ++ .../workspace/code-lens-refresh.rst | 9 +++ docs/capabilities/workspace/configuration.rst | 16 ++++++ .../capabilities/workspace/executeCommand.rst | 6 ++ .../workspace/file-operations.rst | 56 +++++++++++++++++++ .../workspace/inlay-hint-refresh.rst | 9 +++ .../workspace/inline-value-refresh.rst | 9 +++ docs/capabilities/workspace/symbol.rst | 9 +++ .../workspace/workspace-folders.rst | 6 ++ docs/index.rst | 55 +++++++++++++++++- 45 files changed, 655 insertions(+), 2 deletions(-) create mode 100644 docs/capabilities/text-document.rst create mode 100644 docs/capabilities/text-document/code-action.rst create mode 100644 docs/capabilities/text-document/code-lens.rst create mode 100644 docs/capabilities/text-document/completion.rst create mode 100644 docs/capabilities/text-document/declaration.rst create mode 100644 docs/capabilities/text-document/definition.rst create mode 100644 docs/capabilities/text-document/diagnostic.rst create mode 100644 docs/capabilities/text-document/document-color.rst create mode 100644 docs/capabilities/text-document/document-highlight.rst create mode 100644 docs/capabilities/text-document/document-link.rst create mode 100644 docs/capabilities/text-document/document-symbols.rst create mode 100644 docs/capabilities/text-document/folding-range.rst create mode 100644 docs/capabilities/text-document/formatting.rst create mode 100644 docs/capabilities/text-document/hover.rst create mode 100644 docs/capabilities/text-document/implementation.rst create mode 100644 docs/capabilities/text-document/inlay-hint.rst create mode 100644 docs/capabilities/text-document/inline-value.rst create mode 100644 docs/capabilities/text-document/linked-editing-range.rst create mode 100644 docs/capabilities/text-document/moniker.rst create mode 100644 docs/capabilities/text-document/on-type-formatting.rst create mode 100644 docs/capabilities/text-document/preapare-call-hierachy.rst create mode 100644 docs/capabilities/text-document/preapare-type-hierachy.rst create mode 100644 docs/capabilities/text-document/publish-diagnostics.rst create mode 100644 docs/capabilities/text-document/range-formatting.rst create mode 100644 docs/capabilities/text-document/references.rst create mode 100644 docs/capabilities/text-document/rename.rst create mode 100644 docs/capabilities/text-document/selection-range.rst create mode 100644 docs/capabilities/text-document/semantic-tokens.rst create mode 100644 docs/capabilities/text-document/signature-help.rst create mode 100644 docs/capabilities/text-document/type-definition.rst create mode 100644 docs/capabilities/window.rst create mode 100644 docs/capabilities/window/progress.rst create mode 100644 docs/capabilities/window/show-document.rst create mode 100644 docs/capabilities/window/show-message.rst create mode 100644 docs/capabilities/workspace.rst create mode 100644 docs/capabilities/workspace/apply-edit.rst create mode 100644 docs/capabilities/workspace/code-lens-refresh.rst create mode 100644 docs/capabilities/workspace/configuration.rst create mode 100644 docs/capabilities/workspace/executeCommand.rst create mode 100644 docs/capabilities/workspace/file-operations.rst create mode 100644 docs/capabilities/workspace/inlay-hint-refresh.rst create mode 100644 docs/capabilities/workspace/inline-value-refresh.rst create mode 100644 docs/capabilities/workspace/symbol.rst create mode 100644 docs/capabilities/workspace/workspace-folders.rst diff --git a/docs/capabilities/text-document.rst b/docs/capabilities/text-document.rst new file mode 100644 index 0000000..2c9beb9 --- /dev/null +++ b/docs/capabilities/text-document.rst @@ -0,0 +1,8 @@ +Text Document +============= + +.. toctree:: + :maxdepth: 1 + :glob: + + text-document/* diff --git a/docs/capabilities/text-document/code-action.rst b/docs/capabilities/text-document/code-action.rst new file mode 100644 index 0000000..7e0d351 --- /dev/null +++ b/docs/capabilities/text-document/code-action.rst @@ -0,0 +1,29 @@ +``textDocument/codeAction`` +=========================== + +Capabilities relating to the :lsp:`textDocument/codeAction` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.code_action.dynamic_registration + +Honors Change Annotations +------------------------- + +.. capabilities:bool-table:: text_document.code_action.honors_change_annotations + +``CodeAction.isPreferred`` +-------------------------- + +.. capabilities:bool-table:: text_document.code_action.is_preferred_support + +``CodeAction.disabled`` +----------------------- + +.. capabilities:bool-table:: text_document.code_action.disabled_support + +``CodeAction.data`` +------------------- + +.. capabilities:bool-table:: text_document.code_action.data_support diff --git a/docs/capabilities/text-document/code-lens.rst b/docs/capabilities/text-document/code-lens.rst new file mode 100644 index 0000000..4371683 --- /dev/null +++ b/docs/capabilities/text-document/code-lens.rst @@ -0,0 +1,9 @@ +``textDocument/codeLens`` +========================= + +Capabilities relating to the :lsp:`textDocument/codeLens` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.code_lens.dynamic_registration diff --git a/docs/capabilities/text-document/completion.rst b/docs/capabilities/text-document/completion.rst new file mode 100644 index 0000000..c93d599 --- /dev/null +++ b/docs/capabilities/text-document/completion.rst @@ -0,0 +1,40 @@ +``textDocument/completion`` +=========================== + +Dynamic Registration +-------------------- + +Capabilities relating to the :lsp:`textDocument/completion` request. + +.. capabilities:bool-table:: text_document.completion.dynamic_registration + + +``CompletionItem.commitCharactersSupport`` +------------------------------------------ + +.. capabilities:bool-table:: text_document.completion.completion_item.commit_characters_support + +``CompletionItem.deprecatedSupport`` +------------------------------------ + +.. capabilities:bool-table:: text_document.completion.completion_item.deprecated_support + +``CompletionItem.insertReplaceSupport`` +--------------------------------------- + +.. capabilities:bool-table:: text_document.completion.completion_item.insert_replace_support + +``CompletionItem.labelDetailsSupport`` +-------------------------------------- + +.. capabilities:bool-table:: text_document.completion.completion_item.label_details_support + +``CompletionItem.preselectSupport`` +----------------------------------- + +.. capabilities:bool-table:: text_document.completion.completion_item.preselect_support + +``CompletionItem.snippetSupport`` +--------------------------------- + +.. capabilities:bool-table:: text_document.completion.completion_item.snippet_support diff --git a/docs/capabilities/text-document/declaration.rst b/docs/capabilities/text-document/declaration.rst new file mode 100644 index 0000000..a13f91b --- /dev/null +++ b/docs/capabilities/text-document/declaration.rst @@ -0,0 +1,14 @@ +``textDocument/declaration`` +============================ + +Capabilities relating to the :lsp:`textDocument/declaration` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.declaration.dynamic_registration + +Link Support +------------ + +.. capabilities:bool-table:: text_document.declaration.link_support diff --git a/docs/capabilities/text-document/definition.rst b/docs/capabilities/text-document/definition.rst new file mode 100644 index 0000000..5948986 --- /dev/null +++ b/docs/capabilities/text-document/definition.rst @@ -0,0 +1,14 @@ +``textDocument/definition`` +============================ + +Capabilities relating to the :lsp:`textDocument/definition` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.definition.dynamic_registration + +Link Support +------------ + +.. capabilities:bool-table:: text_document.definition.link_support diff --git a/docs/capabilities/text-document/diagnostic.rst b/docs/capabilities/text-document/diagnostic.rst new file mode 100644 index 0000000..8759012 --- /dev/null +++ b/docs/capabilities/text-document/diagnostic.rst @@ -0,0 +1,14 @@ +``textDocument/diagnostic`` +=========================== + +Capabilities relating to the :lsp:`textDocument/diagnostic` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.diagnostic.dynamic_registration + +Related Document Support +------------------------ + +.. capabilities:bool-table:: text_document.diagnostic.related_document_support diff --git a/docs/capabilities/text-document/document-color.rst b/docs/capabilities/text-document/document-color.rst new file mode 100644 index 0000000..fed42d6 --- /dev/null +++ b/docs/capabilities/text-document/document-color.rst @@ -0,0 +1,9 @@ +``textDocument/documentColor`` +============================== + +Capabilities relating to the :lsp:`textDocument/documentColor` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.color_provider.dynamic_registration diff --git a/docs/capabilities/text-document/document-highlight.rst b/docs/capabilities/text-document/document-highlight.rst new file mode 100644 index 0000000..78db079 --- /dev/null +++ b/docs/capabilities/text-document/document-highlight.rst @@ -0,0 +1,9 @@ +``textDocument/documentHighlight`` +================================== + +Capabilities relating to the :lsp:`textDocument/documentHighlight` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.document_highlight.dynamic_registration diff --git a/docs/capabilities/text-document/document-link.rst b/docs/capabilities/text-document/document-link.rst new file mode 100644 index 0000000..b42551f --- /dev/null +++ b/docs/capabilities/text-document/document-link.rst @@ -0,0 +1,14 @@ +``textDocument/documentLink`` +================================== + +Capabilities relating to the :lsp:`textDocument/documentLink` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.document_link.dynamic_registration + +Tooltip Support +--------------- + +.. capabilities:bool-table:: text_document.document_link.tooltip_support diff --git a/docs/capabilities/text-document/document-symbols.rst b/docs/capabilities/text-document/document-symbols.rst new file mode 100644 index 0000000..7b90608 --- /dev/null +++ b/docs/capabilities/text-document/document-symbols.rst @@ -0,0 +1,19 @@ +``textDocument/documentSymbols`` +================================ + +Capabilities relating to the :lsp:`textDocument/documentSymbols` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.document_symbol.dynamic_registration + +Hierarchical Symbols +-------------------- + +.. capabilities:bool-table:: text_document.document_symbol.hierarchical_document_symbol_support + +Label Support +------------- + +.. capabilities:bool-table:: text_document.document_symbol.label_support diff --git a/docs/capabilities/text-document/folding-range.rst b/docs/capabilities/text-document/folding-range.rst new file mode 100644 index 0000000..fb385d3 --- /dev/null +++ b/docs/capabilities/text-document/folding-range.rst @@ -0,0 +1,14 @@ +``textDocument/foldingRange`` +============================= + +Capabilities relating to the :lsp:`textDocument/foldingRange` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.folding_range.dynamic_registration + +Line Folding Only +----------------- + +.. capabilities:bool-table:: text_document.folding_range.line_folding_only diff --git a/docs/capabilities/text-document/formatting.rst b/docs/capabilities/text-document/formatting.rst new file mode 100644 index 0000000..36cb558 --- /dev/null +++ b/docs/capabilities/text-document/formatting.rst @@ -0,0 +1,9 @@ +``textDocument/formatting`` +============================= + +Capabilities relating to the :lsp:`textDocument/formatting` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.formatting.dynamic_registration diff --git a/docs/capabilities/text-document/hover.rst b/docs/capabilities/text-document/hover.rst new file mode 100644 index 0000000..fc5ab6e --- /dev/null +++ b/docs/capabilities/text-document/hover.rst @@ -0,0 +1,9 @@ +``textDocument/hover`` +====================== + +Capabilities relating to the :lsp:`textDocument/hover` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.hover.dynamic_registration diff --git a/docs/capabilities/text-document/implementation.rst b/docs/capabilities/text-document/implementation.rst new file mode 100644 index 0000000..2855024 --- /dev/null +++ b/docs/capabilities/text-document/implementation.rst @@ -0,0 +1,14 @@ +``textDocument/implementation`` +=============================== + +Capabilities relating to the :lsp:`textDocument/implementation` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.implementation.dynamic_registration + +Link Support +------------ + +.. capabilities:bool-table:: text_document.implementation.link_support diff --git a/docs/capabilities/text-document/inlay-hint.rst b/docs/capabilities/text-document/inlay-hint.rst new file mode 100644 index 0000000..1b9d9c2 --- /dev/null +++ b/docs/capabilities/text-document/inlay-hint.rst @@ -0,0 +1,9 @@ +``textDocument/inlayHint`` +========================== + +Capabilities relating to the :lsp:`textDocument/inlayHint` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.inlay_hint.dynamic_registration diff --git a/docs/capabilities/text-document/inline-value.rst b/docs/capabilities/text-document/inline-value.rst new file mode 100644 index 0000000..82e53e5 --- /dev/null +++ b/docs/capabilities/text-document/inline-value.rst @@ -0,0 +1,9 @@ +``textDocument/inlineValue`` +============================ + +Capabilities relating to the :lsp:`textDocument/inlineValue` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.inline_value.dynamic_registration diff --git a/docs/capabilities/text-document/linked-editing-range.rst b/docs/capabilities/text-document/linked-editing-range.rst new file mode 100644 index 0000000..6c14a21 --- /dev/null +++ b/docs/capabilities/text-document/linked-editing-range.rst @@ -0,0 +1,9 @@ +``textDocument/linkedEditingRange`` +=================================== + +Capabilities relating to the :lsp:`textDocument/linkedEditingRange` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.linked_editing_range.dynamic_registration diff --git a/docs/capabilities/text-document/moniker.rst b/docs/capabilities/text-document/moniker.rst new file mode 100644 index 0000000..8c961ef --- /dev/null +++ b/docs/capabilities/text-document/moniker.rst @@ -0,0 +1,9 @@ +``textDocument/moniker`` +======================== + +Capabilities relating to the :lsp:`textDocument/moniker` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.moniker.dynamic_registration diff --git a/docs/capabilities/text-document/on-type-formatting.rst b/docs/capabilities/text-document/on-type-formatting.rst new file mode 100644 index 0000000..ccee49f --- /dev/null +++ b/docs/capabilities/text-document/on-type-formatting.rst @@ -0,0 +1,9 @@ +``textDocument/onTypeFormatting`` +================================= + +Capabilities relating to the :lsp:`textDocument/onTypeFormatting` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.on_type_formatting.dynamic_registration diff --git a/docs/capabilities/text-document/preapare-call-hierachy.rst b/docs/capabilities/text-document/preapare-call-hierachy.rst new file mode 100644 index 0000000..89718e9 --- /dev/null +++ b/docs/capabilities/text-document/preapare-call-hierachy.rst @@ -0,0 +1,9 @@ +``textDocument/prepareCallHierarchy`` +===================================== + +Capabilities relating to the :lsp:`textDocument/prepareCallHierarchy` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.call_hierarchy.dynamic_registration diff --git a/docs/capabilities/text-document/preapare-type-hierachy.rst b/docs/capabilities/text-document/preapare-type-hierachy.rst new file mode 100644 index 0000000..cbe8607 --- /dev/null +++ b/docs/capabilities/text-document/preapare-type-hierachy.rst @@ -0,0 +1,9 @@ +``textDocument/prepareTypeHierarchy`` +===================================== + +Capabilities relating to the :lsp:`textDocument/prepareTypeHierarchy` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.type_hierarchy.dynamic_registration diff --git a/docs/capabilities/text-document/publish-diagnostics.rst b/docs/capabilities/text-document/publish-diagnostics.rst new file mode 100644 index 0000000..86a36b2 --- /dev/null +++ b/docs/capabilities/text-document/publish-diagnostics.rst @@ -0,0 +1,24 @@ +``textDocument/publishDiagnostics`` +=================================== + +Capabilities relating to the :lsp:`textDocument/publishDiagnostics` notification. + +Related Information +------------------- + +.. capabilities:bool-table:: text_document.publish_diagnostics.related_information + +Version Support +--------------- + +.. capabilities:bool-table:: text_document.publish_diagnostics.version_support + +Code Description +---------------- + +.. capabilities:bool-table:: text_document.publish_diagnostics.code_description + +Data Support +------------ + +.. capabilities:bool-table:: text_document.publish_diagnostics.data_support diff --git a/docs/capabilities/text-document/range-formatting.rst b/docs/capabilities/text-document/range-formatting.rst new file mode 100644 index 0000000..8530156 --- /dev/null +++ b/docs/capabilities/text-document/range-formatting.rst @@ -0,0 +1,9 @@ +``textDocument/rangeFormatting`` +================================ + +Capabilities relating to the :lsp:`textDocument/rangeFormatting` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.range_formatting.dynamic_registration diff --git a/docs/capabilities/text-document/references.rst b/docs/capabilities/text-document/references.rst new file mode 100644 index 0000000..934a69b --- /dev/null +++ b/docs/capabilities/text-document/references.rst @@ -0,0 +1,9 @@ +``textDocument/references`` +=============================== + +Capabilities relating to the :lsp:`textDocument/references` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.references.dynamic_registration diff --git a/docs/capabilities/text-document/rename.rst b/docs/capabilities/text-document/rename.rst new file mode 100644 index 0000000..18d2e84 --- /dev/null +++ b/docs/capabilities/text-document/rename.rst @@ -0,0 +1,19 @@ +``textDocument/rename`` +======================= + +Capabilities relating to the :lsp:`textDocument/rename` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.rename.dynamic_registration + +Prepare Support +--------------- + +.. capabilities:bool-table:: text_document.rename.prepare_support + +Honors Change Annotations +------------------------- + +.. capabilities:bool-table:: text_document.rename.honors_change_annotations diff --git a/docs/capabilities/text-document/selection-range.rst b/docs/capabilities/text-document/selection-range.rst new file mode 100644 index 0000000..d23007e --- /dev/null +++ b/docs/capabilities/text-document/selection-range.rst @@ -0,0 +1,9 @@ +``textDocument/selectionRange`` +=============================== + +Capabilities relating to the :lsp:`textDocument/selectionRange` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.selection_range.dynamic_registration diff --git a/docs/capabilities/text-document/semantic-tokens.rst b/docs/capabilities/text-document/semantic-tokens.rst new file mode 100644 index 0000000..b12778b --- /dev/null +++ b/docs/capabilities/text-document/semantic-tokens.rst @@ -0,0 +1,45 @@ +``textDocument/semanticTokens`` +=============================== + +Capabilities relating to :lsp:`textDocument/semanticTokens`. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.semantic_tokens.dynamic_registration + +``textDocument/semanticTokens/range`` +------------------------------------- + +.. capabilities:bool-table:: text_document.semantic_tokens.requests.range + +``textDocument/semanticTokens/full`` +------------------------------------- + +.. capabilities:bool-table:: text_document.semantic_tokens.requests.full + +``textDocument/semanticTokens/full/delta`` +------------------------------------------ + +.. capabilities:bool-table:: text_document.semantic_tokens.requests.full.delta + + +Overlapping Tokens +------------------ + +.. capabilities:bool-table:: text_document.semantic_tokens.overlapping_token_support + +Multiline Tokens +---------------- + +.. capabilities:bool-table:: text_document.semantic_tokens.multiline_token_support + +Server Cancel Support +--------------------- + +.. capabilities:bool-table:: text_document.semantic_tokens.server_cancel_support + +Augments Syntax Tokens +---------------------- + +.. capabilities:bool-table:: text_document.semantic_tokens.augments_syntax_tokens diff --git a/docs/capabilities/text-document/signature-help.rst b/docs/capabilities/text-document/signature-help.rst new file mode 100644 index 0000000..e268549 --- /dev/null +++ b/docs/capabilities/text-document/signature-help.rst @@ -0,0 +1,24 @@ +``textDocument/signatureHelp`` +============================== + +Capabilities relating to the :lsp:`textDocument/signatureHelp` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.signature_help.dynamic_registration + +Label Offset Support +-------------------- + +.. capabilities:bool-table:: text_document.signature_help.signature_information.parameter_information.label_offset_support + +Active Parameter Support +------------------------ + +.. capabilities:bool-table:: text_document.signature_help.signature_information.active_parameter_support + +Context Support +--------------- + +.. capabilities:bool-table:: text_document.signature_help.context_support diff --git a/docs/capabilities/text-document/type-definition.rst b/docs/capabilities/text-document/type-definition.rst new file mode 100644 index 0000000..3f0c9d7 --- /dev/null +++ b/docs/capabilities/text-document/type-definition.rst @@ -0,0 +1,14 @@ +``textDocument/typeDefinition`` +=============================== + +Capabilities relating to the :lsp:`textDocument/typeDefinition` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: text_document.type_definition.dynamic_registration + +Link Support +------------ + +.. capabilities:bool-table:: text_document.type_definition.link_support diff --git a/docs/capabilities/window.rst b/docs/capabilities/window.rst new file mode 100644 index 0000000..e5e6a0c --- /dev/null +++ b/docs/capabilities/window.rst @@ -0,0 +1,8 @@ +Window +====== + +.. toctree:: + :maxdepth: 1 + :glob: + + window/* diff --git a/docs/capabilities/window/progress.rst b/docs/capabilities/window/progress.rst new file mode 100644 index 0000000..f882024 --- /dev/null +++ b/docs/capabilities/window/progress.rst @@ -0,0 +1,4 @@ +``window/workDoneProgress/create`` +================================== + +.. capabilities:bool-table:: window.work_done_progress diff --git a/docs/capabilities/window/show-document.rst b/docs/capabilities/window/show-document.rst new file mode 100644 index 0000000..0749e7f --- /dev/null +++ b/docs/capabilities/window/show-document.rst @@ -0,0 +1,6 @@ +``window/showDocument`` +======================= + +Capabilities relating to the :lsp:`window/showDocument` request. + +.. capabilities:bool-table:: window.show_document.support diff --git a/docs/capabilities/window/show-message.rst b/docs/capabilities/window/show-message.rst new file mode 100644 index 0000000..41b01da --- /dev/null +++ b/docs/capabilities/window/show-message.rst @@ -0,0 +1,9 @@ +``window/showMessageRequest`` +============================= + +Capabilities relating to the :lsp:`window/showMessageRequest` request. + +Additional Properties Support +----------------------------- + +.. capabilities:bool-table:: window.show_message.message_action_item.additional_properties_support diff --git a/docs/capabilities/workspace.rst b/docs/capabilities/workspace.rst new file mode 100644 index 0000000..cd46a86 --- /dev/null +++ b/docs/capabilities/workspace.rst @@ -0,0 +1,8 @@ +Workspace +========= + +.. toctree:: + :maxdepth: 1 + :glob: + + workspace/* diff --git a/docs/capabilities/workspace/apply-edit.rst b/docs/capabilities/workspace/apply-edit.rst new file mode 100644 index 0000000..ffa5f13 --- /dev/null +++ b/docs/capabilities/workspace/apply-edit.rst @@ -0,0 +1,6 @@ +``workspace/applyEdit`` +======================= + +Capabilities relating to the :lsp:`workspace/applyEdit` request. + +.. capabilities:bool-table:: workspace.apply_edit diff --git a/docs/capabilities/workspace/code-lens-refresh.rst b/docs/capabilities/workspace/code-lens-refresh.rst new file mode 100644 index 0000000..b4924ea --- /dev/null +++ b/docs/capabilities/workspace/code-lens-refresh.rst @@ -0,0 +1,9 @@ +``workspace/codeLens/refresh`` +============================== + +Capabilities relating to the :lsp:`workspace/codeLens/refresh` request. + +Refresh Support +--------------- + +.. capabilities:bool-table:: workspace.code_lens.refresh_support diff --git a/docs/capabilities/workspace/configuration.rst b/docs/capabilities/workspace/configuration.rst new file mode 100644 index 0000000..f867146 --- /dev/null +++ b/docs/capabilities/workspace/configuration.rst @@ -0,0 +1,16 @@ +``workspace/configuration`` +=========================== + +Capabilities relating to the :lsp:`workspace/configuration` request. + +.. capabilities:bool-table:: workspace.configuration + +``workspace/didChangeConfiguration`` +==================================== + +Capabilities relating to the :lsp:`workspace/didChangeConfiguration` notification. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: workspace.did_change_configuration.dynamic_registration diff --git a/docs/capabilities/workspace/executeCommand.rst b/docs/capabilities/workspace/executeCommand.rst new file mode 100644 index 0000000..e11bf54 --- /dev/null +++ b/docs/capabilities/workspace/executeCommand.rst @@ -0,0 +1,6 @@ +``workspace/executeCommand`` +============================ + +Capabilities relating to the :lsp:`workspace/executeCommand` request. + +.. capabilities:bool-table:: workspace.execute_command.dynamic_registration diff --git a/docs/capabilities/workspace/file-operations.rst b/docs/capabilities/workspace/file-operations.rst new file mode 100644 index 0000000..0ee78f7 --- /dev/null +++ b/docs/capabilities/workspace/file-operations.rst @@ -0,0 +1,56 @@ +``workspace/willCreateFiles`` +============================= + +Capabilities relating to the :lsp:`workspace/willCreateFiles` request. + +.. capabilities:bool-table:: workspace.file_operations.will_create + +``workspace/didCreateFiles`` +============================= + +Capabilities relating to the :lsp:`workspace/didCreateFiles` notification. + +.. capabilities:bool-table:: workspace.file_operations.did_create + +``workspace/willRenameFiles`` +============================= + +Capabilities relating to the :lsp:`workspace/willRenameFiles` request. + +.. capabilities:bool-table:: workspace.file_operations.will_rename + +``workspace/didRenameFiles`` +============================= + +Capabilities relating to the :lsp:`workspace/didRenameFiles` notification. + +.. capabilities:bool-table:: workspace.file_operations.did_rename + +``workspace/willDeleteFiles`` +============================= + +Capabilities relating to the :lsp:`workspace/willDeleteFiles` request. + +.. capabilities:bool-table:: workspace.file_operations.will_delete + +``workspace/didDeleteFiles`` +============================= + +Capabilities relating to the :lsp:`workspace/didDeleteFiles` notification. + +.. capabilities:bool-table:: workspace.file_operations.did_delete + +``workspace/didChangeWatchedFiles`` +=================================== + +Capabilities relating to the :lsp:`workspace/didChangeWatchedFiles` notification. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: workspace.did_change_watched_files.dynamic_registration + +Relative Pattern Support +------------------------ + +.. capabilities:bool-table:: workspace.did_change_watched_files.relative_pattern_support diff --git a/docs/capabilities/workspace/inlay-hint-refresh.rst b/docs/capabilities/workspace/inlay-hint-refresh.rst new file mode 100644 index 0000000..6233876 --- /dev/null +++ b/docs/capabilities/workspace/inlay-hint-refresh.rst @@ -0,0 +1,9 @@ +``workspace/inlayHint/refresh`` +=============================== + +Capabilities relating to the :lsp:`workspace/inlayHint/refresh` request. + +Refresh Support +--------------- + +.. capabilities:bool-table:: workspace.inlay_hint.refresh_support diff --git a/docs/capabilities/workspace/inline-value-refresh.rst b/docs/capabilities/workspace/inline-value-refresh.rst new file mode 100644 index 0000000..6035a7b --- /dev/null +++ b/docs/capabilities/workspace/inline-value-refresh.rst @@ -0,0 +1,9 @@ +``workspace/inlineValue/refresh`` +================================= + +Capabilities relating to the :lsp:`workspace/inlineValue/refresh` request. + +Rehresh Support +--------------- + +.. capabilities:bool-table:: workspace.inline_value.refresh_support diff --git a/docs/capabilities/workspace/symbol.rst b/docs/capabilities/workspace/symbol.rst new file mode 100644 index 0000000..607cd0a --- /dev/null +++ b/docs/capabilities/workspace/symbol.rst @@ -0,0 +1,9 @@ +``workspace/symbol`` +==================== + +Capabilities relating to the :lsp:`workspace/symbol` request. + +Dynamic Registration +-------------------- + +.. capabilities:bool-table:: workspace.symbol.dynamic_registration diff --git a/docs/capabilities/workspace/workspace-folders.rst b/docs/capabilities/workspace/workspace-folders.rst new file mode 100644 index 0000000..82dffdc --- /dev/null +++ b/docs/capabilities/workspace/workspace-folders.rst @@ -0,0 +1,6 @@ +``workspace/workspaceFolders`` +============================== + +Capabilities relating to the :lsp:`workspace/workspaceFolders` request. + +.. capabilities:bool-table:: workspace.workspace_folders diff --git a/docs/index.rst b/docs/index.rst index b274137..200b07e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,8 +1,57 @@ LSP Devtools ============ -The LSP Devtools project provides a number of tools that aim to make the -process of developing language servers and clients easier. +The LSP Devtools project provides a number of tools for making the the +process of developing language servers easier. + +Client Capability Index +----------------------- + +.. warning:: + + This is still under construction. + +.. important:: + + This accuracy of this section entirely depends on the captured capabilities data that is `bundled `__ with pytest-lsp. + + Pull requests for corrections and new data welcome! + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Capabilities + + capabilities/text-document + capabilities/workspace + capabilities/window + +Inspired by `caniuse.com `__ this provides information on which clients support which features of the `LSP Specification `__. + +.. grid:: 2 + :gutter: 2 + + .. grid-item-card:: Text Document + :columns: 12 + :link: /capabilities/text-document + :link-type: doc + :text-align: center + + Capabilities for text document methods like completion, code actions and more. + + .. grid-item-card:: Window + :link: /capabilities/window + :link-type: doc + :text-align: center + + Work done progress, show document and message requests + + .. grid-item-card:: Workspace + :link: /capabilities/workspace + :link-type: doc + :text-align: center + + File operations, workspace folders and configuration lsp-devtools ------------ @@ -15,6 +64,8 @@ lsp-devtools lsp-devtools/changelog +.. figure:: https://user-images.githubusercontent.com/2675694/273293510-e43fdc92-03dd-40c9-aaca-ddb5e526031a.png + The `lsp-devtools `_ package provides a collection of CLI utilities that help inspect and visualise the interactions between a language client and a server. See the :doc:`lsp-devtools/guide/getting-started` guide for details. From 411b9621fe4f449ad0f29e1f553fe380e3f5092e Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 18 Oct 2023 22:12:11 +0100 Subject: [PATCH 10/50] lsp-devtools: formatting --- lib/lsp-devtools/CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/lsp-devtools/CHANGES.rst b/lib/lsp-devtools/CHANGES.rst index 93ee611..bdc13a8 100644 --- a/lib/lsp-devtools/CHANGES.rst +++ b/lib/lsp-devtools/CHANGES.rst @@ -46,6 +46,7 @@ Features It is now capable of live streaming messages sent between a client and server to stdout, plain text files or a SQLite database. It also offers a number of filters for selecting the messages you wish to record, as well as a (WIP!) format string syntax for controlling how messages are formatted. (`#26 `_) + - Add ``tui``command. A proof of concept devtools TUI implemented in textual, that live updates with the LSP messages sent between client and server! From d2e45f35c3b6607b7d9da373902837acd02fcd4a Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 18 Oct 2023 23:55:39 +0100 Subject: [PATCH 11/50] workflow: Create workflow for capturing neovim capabilities --- .github/workflows/capabilities-nvim.yml | 42 +++++++++++++++++++++++++ scripts/nvim-capabilities.lua | 21 +++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 .github/workflows/capabilities-nvim.yml create mode 100644 scripts/nvim-capabilities.lua diff --git a/.github/workflows/capabilities-nvim.yml b/.github/workflows/capabilities-nvim.yml new file mode 100644 index 0000000..11985ab --- /dev/null +++ b/.github/workflows/capabilities-nvim.yml @@ -0,0 +1,42 @@ +name: Neovim Capabilities +on: + workflow_dispatch: + inputs: + version: + description: 'Version to capture capabilities for' + required: true + type: string + +jobs: + capture: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - run: | + gh release download ${{ inputs.version }} -p '*.appimage' -R neovim/neovim + ls -l + + chmod +x nvim.appimage + ./nvim.appimage -l scripts/nvim-capabilities.lua + + mv neovim_v*.json lib/pytest-lsp/pytest_lsp/clients/ + ls -l + + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config user.name "github-actions[bot]" + + git checkout -b neovim-${{ inputs.version }}-capabilities + git add lib/pytest-lsp/pytest_lsp/clients/ + git commit -m "Add client capabilities for Neovim ${{ inputs.version }}" + git push -u origin neovim-${{ inputs.version }}-capabilities + + gh pr create --base develop --fill + name: Capture Neovim Capailities + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/nvim-capabilities.lua b/scripts/nvim-capabilities.lua new file mode 100644 index 0000000..47b6e44 --- /dev/null +++ b/scripts/nvim-capabilities.lua @@ -0,0 +1,21 @@ +-- Dump the client capabilities for this version of neovim. +local version_info = vim.version() +local version = string.format('%d.%d.%d', version_info.major, version_info.minor, version_info.patch) + +local params = { + clientInfo = { + name = 'Neovim', + version = version, + }, + capabilities = vim.lsp.protocol.make_client_capabilities(), +} + +local json = vim.json.encode(params) +local bufnr = vim.api.nvim_create_buf(true, false) +vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { json }) + +vim.api.nvim_buf_call(bufnr, function() + vim.cmd(string.format(':w neovim_v%s.json', version)) + vim.cmd('.!python -m json.tool %') + vim.cmd(':w') +end) From 5ffcc5c8358a2b10b2a42d216e87951799573eb1 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Thu, 19 Oct 2023 00:08:45 +0100 Subject: [PATCH 12/50] workflow: FUSE workaround --- .github/workflows/capabilities-nvim.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/capabilities-nvim.yml b/.github/workflows/capabilities-nvim.yml index 11985ab..35ee4ec 100644 --- a/.github/workflows/capabilities-nvim.yml +++ b/.github/workflows/capabilities-nvim.yml @@ -23,7 +23,8 @@ jobs: ls -l chmod +x nvim.appimage - ./nvim.appimage -l scripts/nvim-capabilities.lua + ./nvim.appimage --appimage-extract + ./squashfs-root/usr/bin/nvim -l scripts/nvim-capabilities.lua mv neovim_v*.json lib/pytest-lsp/pytest_lsp/clients/ ls -l From 1fb5d8dfa0501f7ae203a853e797c828e209d324 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 23:11:23 +0000 Subject: [PATCH 13/50] Add client capabilities for Neovim v0.9.1 --- .../pytest_lsp/clients/neovim_v0.9.1.json | 288 ++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json new file mode 100644 index 0000000..a0088c3 --- /dev/null +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json @@ -0,0 +1,288 @@ +{ + "clientInfo": { + "version": "0.9.1", + "name": "Neovim" + }, + "capabilities": { + "textDocument": { + "declaration": { + "linkSupport": true + }, + "synchronization": { + "didSave": true, + "willSave": true, + "dynamicRegistration": false, + "willSaveWaitUntil": true + }, + "callHierarchy": { + "dynamicRegistration": false + }, + "codeAction": { + "isPreferredSupport": true, + "dataSupport": true, + "resolveSupport": { + "properties": [ + "edit" + ] + }, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + }, + "dynamicRegistration": false + }, + "publishDiagnostics": { + "tagSupport": { + "valueSet": [ + 1, + 2 + ] + }, + "relatedInformation": true + }, + "rename": { + "dynamicRegistration": false, + "prepareSupport": true + }, + "implementation": { + "linkSupport": true + }, + "typeDefinition": { + "linkSupport": true + }, + "documentSymbol": { + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "dynamicRegistration": false, + "hierarchicalDocumentSymbolSupport": true + }, + "signatureHelp": { + "dynamicRegistration": false, + "signatureInformation": { + "parameterInformation": { + "labelOffsetSupport": true + }, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "activeParameterSupport": true + } + }, + "hover": { + "dynamicRegistration": false, + "contentFormat": [ + "markdown", + "plaintext" + ] + }, + "definition": { + "linkSupport": true + }, + "completion": { + "contextSupport": false, + "completionItem": { + "preselectSupport": false, + "deprecatedSupport": false, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "snippetSupport": false, + "commitCharactersSupport": false + }, + "dynamicRegistration": false, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + } + }, + "semanticTokens": { + "augmentsSyntaxTokens": true, + "requests": { + "range": false, + "full": { + "delta": true + } + }, + "tokenModifiers": [ + "declaration", + "definition", + "readonly", + "static", + "deprecated", + "abstract", + "async", + "modification", + "documentation", + "defaultLibrary" + ], + "formats": [ + "relative" + ], + "dynamicRegistration": false, + "tokenTypes": [ + "namespace", + "type", + "class", + "enum", + "interface", + "struct", + "typeParameter", + "parameter", + "variable", + "property", + "enumMember", + "event", + "function", + "method", + "macro", + "keyword", + "modifier", + "comment", + "string", + "number", + "regexp", + "operator", + "decorator" + ], + "overlappingTokenSupport": true, + "multilineTokenSupport": false, + "serverCancelSupport": false + }, + "references": { + "dynamicRegistration": false + }, + "documentHighlight": { + "dynamicRegistration": false + } + }, + "window": { + "showDocument": { + "support": true + }, + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": false + } + } + }, + "workspace": { + "workspaceFolders": true, + "configuration": true, + "applyEdit": true, + "workspaceEdit": { + "resourceOperations": [ + "rename", + "create", + "delete" + ] + }, + "semanticTokens": { + "refreshSupport": true + }, + "symbol": { + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "dynamicRegistration": false, + "hierarchicalWorkspaceSymbolSupport": true + }, + "didChangeWatchedFiles": { + "dynamicRegistration": false, + "relativePatternSupport": true + } + } + } +} From a32863a8be5df10e71312803c0b8afe9b3149c44 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 12:33:18 +0100 Subject: [PATCH 14/50] docs: Add support for multiple versions of a client --- docs/ext/capabilities.py | 29 ++++++++++++++++++++++++++--- docs/ext/supported_clients.py | 4 +++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/ext/capabilities.py b/docs/ext/capabilities.py index b0df22c..74f4885 100644 --- a/docs/ext/capabilities.py +++ b/docs/ext/capabilities.py @@ -3,13 +3,16 @@ import pathlib import re import typing +from typing import Dict from typing import List +from typing import Optional import attrs from docutils import nodes from docutils.parsers.rst import directives from lsprotocol import types from lsprotocol.converters import get_converter +from packaging.version import parse as parse_version from pygls.capabilities import get_capability from sphinx.application import Sphinx from sphinx.domains import Domain @@ -37,19 +40,39 @@ def build_header(self): return header, colspecs - def build_body(self, capability: str): - rows = [] + def get_client_support_for(self, capability: str) -> Dict[str, Optional[str]]: + """Build a dictionary containing the clients that support the given capability + as well as the version that support was introduced in.""" domain = self.env.domains["capabilities"] + clients: Dict[str, Optional[str]] = {} for (name, version), capabilities in domain.clients.items(): supported = get_capability(capabilities, capability, False) + + if not supported: + if name not in clients: + clients[name] = None + continue + + if (existing := clients.get(name, None)) is None: + clients[name] = version + else: + clients[name] = min(existing, version, key=parse_version) + + return clients + + def build_body(self, capability: str): + rows = [] + clients = self.get_client_support_for(capability) + + for name, version in clients.items(): rows.append( nodes.row( "", nodes.entry("", nodes.Text(name)), nodes.entry( "", - nodes.Text(version if supported else " - "), + nodes.Text(version or " - "), classes=["centered"], ), ) diff --git a/docs/ext/supported_clients.py b/docs/ext/supported_clients.py index e54f755..4560b2d 100644 --- a/docs/ext/supported_clients.py +++ b/docs/ext/supported_clients.py @@ -2,6 +2,7 @@ from docutils import nodes from docutils.parsers.rst import Directive +from packaging.version import parse as parse_version from sphinx.application import Sphinx @@ -26,6 +27,7 @@ def run(self): clients = self.load_clients() for client, versions in clients.items(): + version_string = ", ".join(sorted(versions, key=parse_version)) rows.append( nodes.row( "", @@ -35,7 +37,7 @@ def run(self): ), nodes.entry( "", - nodes.paragraph("", ", ".join(versions)), + nodes.paragraph("", version_string), ), ), ) From 9e9e163621e56b6b97a1e9ef0922cb7c8015bce5 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 13:15:53 +0100 Subject: [PATCH 15/50] pytest-lsp: Test against released version of pygls It's now current enough that we don't need to follow the latest git snapshot --- lib/pytest-lsp/tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pytest-lsp/tox.ini b/lib/pytest-lsp/tox.ini index 7bf9df9..46aa501 100644 --- a/lib/pytest-lsp/tox.ini +++ b/lib/pytest-lsp/tox.ini @@ -10,7 +10,6 @@ package = wheel wheel_build_env = .pkg deps = coverage[toml] - git+https://github.com/openlawlibrary/pygls commands_pre = coverage erase commands = From 5a800cbdd8d276ec6bd01d9bc31c7e1ea47f80b2 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 15:12:21 +0100 Subject: [PATCH 16/50] pytest-lsp: Add syntax for selecting a specific version of a client --- lib/pytest-lsp/changes/101.enhancement.rst | 2 + lib/pytest-lsp/pyproject.toml | 1 + lib/pytest-lsp/pytest_lsp/client.py | 70 ++++++++++++++++++---- lib/pytest-lsp/tests/test_client.py | 45 +++++++++++--- 4 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 lib/pytest-lsp/changes/101.enhancement.rst diff --git a/lib/pytest-lsp/changes/101.enhancement.rst b/lib/pytest-lsp/changes/101.enhancement.rst new file mode 100644 index 0000000..5397acf --- /dev/null +++ b/lib/pytest-lsp/changes/101.enhancement.rst @@ -0,0 +1,2 @@ +It is now possible to select a specific version of a client when using the ``client_capabilities()`` function. +e.g. ``client-name@latest``, ``client-name@v2`` or ``client-name@2.1.3``. ``pytest-lsp`` will choose the latest available version of the client that satisfies the given constraint. diff --git a/lib/pytest-lsp/pyproject.toml b/lib/pytest-lsp/pyproject.toml index 872a8dd..a8e01a8 100644 --- a/lib/pytest-lsp/pyproject.toml +++ b/lib/pytest-lsp/pyproject.toml @@ -25,6 +25,7 @@ classifiers = [ ] dependencies = [ "importlib-resources; python_version<\"3.9\"", + "packaging", "pygls>=1.1.0", "pytest", "pytest-asyncio", diff --git a/lib/pytest-lsp/pytest_lsp/client.py b/lib/pytest-lsp/pytest_lsp/client.py index ba279e1..e2de7f0 100644 --- a/lib/pytest-lsp/pytest_lsp/client.py +++ b/lib/pytest-lsp/pytest_lsp/client.py @@ -2,8 +2,10 @@ import json import logging import os +import pathlib import sys import traceback +import typing from typing import Dict from typing import List from typing import Optional @@ -11,6 +13,7 @@ from lsprotocol import types from lsprotocol.converters import get_converter +from packaging.version import parse as parse_version from pygls.exceptions import JsonRpcException from pygls.exceptions import PyglsError from pygls.lsp.client import BaseLanguageClient @@ -207,32 +210,73 @@ def show_document( def client_capabilities(client_spec: str) -> types.ClientCapabilities: """Find the capabilities that correspond to the given client spec. + This function supports the following syntax + + ``client-name`` or ``client-name@latest`` + Return the capabilities of the latest version of ``client-name`` + + ``client-name@v2`` + Return the latest release of the ``v2`` of ``client-name`` + + ``client-name@v2.3.1`` + Return exactly ``v2.3.1`` of ``client-name`` + Parameters ---------- client_spec - A string describing the client to load the corresponding + The string describing the client to load the corresponding capabilities for. + + Raises + ------ + ValueError + If the requested client's capabilities could not be found + + Returns + ------- + ClientCapabilities + The requested client capabilities """ - # Currently, we only have a single version of each client so let's just return the - # first one we find. - # - # TODO: Implement support for client@x.y.z - # TODO: Implement support for client@latest? - filename = None + candidates: Dict[str, pathlib.Path] = {} + + client_spec = client_spec.replace("-", "_") + target_version = "latest" + + if "@" in client_spec: + client_spec, target_version = client_spec.split("@") + if target_version.startswith("v"): + target_version = target_version[1:] + for resource in resources.files("pytest_lsp.clients").iterdir(): + filename = typing.cast(pathlib.Path, resource) + # Skip the README or any other files that we don't care about. - if not resource.name.endswith(".json"): + if not filename.suffix == ".json": continue - if resource.name.startswith(client_spec.replace("-", "_")): - filename = resource - break + name, version = filename.stem.split("_v") + if name == client_spec: + if version.startswith(target_version) or target_version == "latest": + candidates[version] = filename + + if len(candidates) == 0: + raise ValueError( + f"Could not find capabilities for '{client_spec}@{target_version}'" + ) - if not filename: - raise ValueError(f"Unknown client: '{client_spec}'") + # Out of the available candidates, choose the latest version + selected_version = sorted(candidates.keys(), key=parse_version, reverse=True)[0] + filename = candidates[selected_version] converter = get_converter() capabilities = json.loads(filename.read_text()) + params = converter.structure(capabilities, types.InitializeParams) + logger.info( + "Selected %s v%s", + params.client_info.name, # type: ignore[union-attr] + params.client_info.version, # type: ignore[union-attr] + ) + return params.capabilities diff --git a/lib/pytest-lsp/tests/test_client.py b/lib/pytest-lsp/tests/test_client.py index 388a031..5ba13b4 100644 --- a/lib/pytest-lsp/tests/test_client.py +++ b/lib/pytest-lsp/tests/test_client.py @@ -5,23 +5,43 @@ import pygls.uris as uri import pytest + import pytest_lsp @pytest.mark.parametrize( - "client_spec,client_capabilities", + "client_spec,capabilities", [ *itertools.product( ["visual_studio_code", "visual-studio-code"], ["visual_studio_code_v1.65.2.json"], ), - ("neovim", "neovim_v0.6.1.json"), + *itertools.product( + ["neovim@0.6", "neovim@v0.6", "neovim@0.6.1"], + ["neovim_v0.6.1.json"], + ), + *itertools.product( + ["neovim", "neovim@latest", "neovim@v0", "neovim@v0.9", "neovim@v0.9.1"], + ["neovim_v0.9.1.json"], + ), ], ) def test_client_capabilities( - pytester: pytest.Pytester, client_spec: str, client_capabilities: str + pytester: pytest.Pytester, client_spec: str, capabilities: str ): - """Ensure that the plugin can mimic the requested client's capabilities.""" + """Ensure that the plugin can mimic the requested client's capabilities correctly. + + Parameters + ---------- + pytester + pytest's built in pytester fixture. + + client_spec + The string used to select the desired client and version + + client_capabilities + The filename containing the expected client capabilities + """ python = sys.executable testdir = pathlib.Path(__file__).parent @@ -29,7 +49,7 @@ def test_client_capabilities( root_uri = uri.from_fs_path(str(testdir)) clients_dir = pathlib.Path(pytest_lsp.__file__).parent / "clients" - with (clients_dir / client_capabilities).open() as f: + with (clients_dir / capabilities).open() as f: # Easiest way to reformat the JSON onto a single line expected = json.dumps(json.load(f)["capabilities"]) @@ -71,14 +91,23 @@ async def client(lsp_client: LanguageClient): f""" import json import pytest -from lsprotocol.types import ExecuteCommandParams +from lsprotocol import types +from lsprotocol.converters import get_converter @pytest.mark.asyncio async def test_capabilities(client): actual = await client.workspace_execute_command_async( - ExecuteCommandParams(command="return.client.capabilities") + types.ExecuteCommandParams(command="return.client.capabilities") ) - assert actual == json.loads('{expected}') + + expected = json.loads('{expected}') + + # lsprotocol is going to filter out any quirks of the client + # so we can't compare the dicts directly. + converter = get_converter() + actual_capabilities = converter.structure(actual, types.ClientCapabilities) + expected_capabilities = converter.structure(expected, types.ClientCapabilities) + assert actual_capabilities == expected_capabilities """ ) From f41349887e11f7d65bb7ab489e436e5362482743 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 15:14:03 +0100 Subject: [PATCH 17/50] pytest-lsp: Drop optional dependencies They were out of date and the source of truth is now in `tox.ini` and `.pre-commit-config.yaml`. --- lib/pytest-lsp/pyproject.toml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/pytest-lsp/pyproject.toml b/lib/pytest-lsp/pyproject.toml index a8e01a8..c48ca36 100644 --- a/lib/pytest-lsp/pyproject.toml +++ b/lib/pytest-lsp/pyproject.toml @@ -39,23 +39,6 @@ dependencies = [ [project.entry-points.pytest11] pytest-lsp = "pytest_lsp" -[project.optional-dependencies] -dev = [ - "black", - "flake8", - "pre-commit", - "tox", -] -test = [ - "pytest", - "pytest-cov", - "pytest-timeout", -] -typecheck = [ - "mypy", - "types-appdirs" -] - [tool.setuptools.packages.find] include = ["pytest_lsp*"] From 1c47c90879e6676bfc00d3a0ae5a3fc34829fad7 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 15:15:37 +0100 Subject: [PATCH 18/50] vscode: Add pytest config --- .vscode/settings.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 76af123..92c06ea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -29,4 +29,9 @@ "docs", "docs/_build" ], + "python.testing.pytestArgs": [ + "lib/pytest-lsp/tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, } From dd0482a6d5e52a07ba8b5d916317061a68a00895 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 16:00:31 +0100 Subject: [PATCH 19/50] pytest-lsp: Add client capabilities for neovim 0.7 and 0.8 --- .../pytest_lsp/clients/neovim_v0.7.0.json | 234 +++++++++++++++++ .../pytest_lsp/clients/neovim_v0.8.0.json | 236 ++++++++++++++++++ 2 files changed, 470 insertions(+) create mode 100644 lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json create mode 100644 lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json new file mode 100644 index 0000000..593f24a --- /dev/null +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json @@ -0,0 +1,234 @@ +{ + "capabilities": { + "window": { + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": false + } + }, + "showDocument": { + "support": false + } + }, + "textDocument": { + "documentSymbol": { + "hierarchicalDocumentSymbolSupport": true, + "dynamicRegistration": false, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + } + }, + "rename": { + "prepareSupport": true, + "dynamicRegistration": false + }, + "references": { + "dynamicRegistration": false + }, + "documentHighlight": { + "dynamicRegistration": false + }, + "hover": { + "contentFormat": [ + "markdown", + "plaintext" + ], + "dynamicRegistration": false + }, + "implementation": { + "linkSupport": true + }, + "synchronization": { + "didSave": true, + "dynamicRegistration": false, + "willSave": false, + "willSaveWaitUntil": false + }, + "declaration": { + "linkSupport": true + }, + "publishDiagnostics": { + "tagSupport": { + "valueSet": [ + 1, + 2 + ] + }, + "relatedInformation": true + }, + "completion": { + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + }, + "dynamicRegistration": false, + "contextSupport": false, + "completionItem": { + "documentationFormat": [ + "markdown", + "plaintext" + ], + "snippetSupport": false, + "commitCharactersSupport": false, + "preselectSupport": false, + "deprecatedSupport": false + } + }, + "definition": { + "linkSupport": true + }, + "typeDefinition": { + "linkSupport": true + }, + "codeAction": { + "resolveSupport": { + "properties": [ + "edit" + ] + }, + "dynamicRegistration": false, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "Empty", + "QuickFix", + "Refactor", + "RefactorExtract", + "RefactorInline", + "RefactorRewrite", + "Source", + "SourceOrganizeImports", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + }, + "dataSupport": true + }, + "signatureHelp": { + "signatureInformation": { + "documentationFormat": [ + "markdown", + "plaintext" + ], + "activeParameterSupport": true, + "parameterInformation": { + "labelOffsetSupport": true + } + }, + "dynamicRegistration": false + } + }, + "callHierarchy": { + "dynamicRegistration": false + }, + "workspace": { + "workspaceEdit": { + "resourceOperations": [ + "rename", + "create", + "delete" + ] + }, + "applyEdit": true, + "symbol": { + "dynamicRegistration": false, + "hierarchicalWorkspaceSymbolSupport": true, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + } + }, + "workspaceFolders": true + } + }, + "clientInfo": { + "name": "Neovim", + "version": "0.7.0" + } +} diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json new file mode 100644 index 0000000..62ff6ba --- /dev/null +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json @@ -0,0 +1,236 @@ +{ + "clientInfo": { + "name": "Neovim", + "version": "0.8.0" + }, + "capabilities": { + "workspace": { + "configuration": true, + "applyEdit": true, + "workspaceEdit": { + "resourceOperations": [ + "rename", + "create", + "delete" + ] + }, + "workspaceFolders": true, + "symbol": { + "dynamicRegistration": false, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "hierarchicalWorkspaceSymbolSupport": true + } + }, + "window": { + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": false + } + }, + "showDocument": { + "support": false + } + }, + "callHierarchy": { + "dynamicRegistration": false + }, + "textDocument": { + "synchronization": { + "didSave": true, + "dynamicRegistration": false, + "willSave": false, + "willSaveWaitUntil": false + }, + "documentSymbol": { + "dynamicRegistration": false, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "hierarchicalDocumentSymbolSupport": true + }, + "declaration": { + "linkSupport": true + }, + "hover": { + "contentFormat": [ + "markdown", + "plaintext" + ], + "dynamicRegistration": false + }, + "definition": { + "linkSupport": true + }, + "implementation": { + "linkSupport": true + }, + "typeDefinition": { + "linkSupport": true + }, + "publishDiagnostics": { + "relatedInformation": true, + "tagSupport": { + "valueSet": [ + 1, + 2 + ] + } + }, + "signatureHelp": { + "signatureInformation": { + "activeParameterSupport": true, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "parameterInformation": { + "labelOffsetSupport": true + } + }, + "dynamicRegistration": false + }, + "rename": { + "prepareSupport": true, + "dynamicRegistration": false + }, + "completion": { + "dynamicRegistration": false, + "completionItem": { + "deprecatedSupport": false, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "commitCharactersSupport": false, + "snippetSupport": false, + "preselectSupport": false + }, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + }, + "contextSupport": false + }, + "documentHighlight": { + "dynamicRegistration": false + }, + "codeAction": { + "dynamicRegistration": false, + "dataSupport": true, + "resolveSupport": { + "properties": [ + "edit" + ] + }, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "Empty", + "QuickFix", + "Refactor", + "RefactorExtract", + "RefactorInline", + "RefactorRewrite", + "Source", + "SourceOrganizeImports", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + }, + "isPreferredSupport": true + }, + "references": { + "dynamicRegistration": false + } + } + } +} From 2d2d416ff5a704745b784534e089fe255cc0f96d Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 16:01:52 +0100 Subject: [PATCH 20/50] pytest-lsp: Update changelog --- lib/pytest-lsp/changes/100.capability.rst | 1 + lib/pytest-lsp/changes/89.capability.rst | 1 + lib/pytest-lsp/pyproject.toml | 1 + 3 files changed, 3 insertions(+) create mode 100644 lib/pytest-lsp/changes/100.capability.rst create mode 100644 lib/pytest-lsp/changes/89.capability.rst diff --git a/lib/pytest-lsp/changes/100.capability.rst b/lib/pytest-lsp/changes/100.capability.rst new file mode 100644 index 0000000..5ef9cce --- /dev/null +++ b/lib/pytest-lsp/changes/100.capability.rst @@ -0,0 +1 @@ +Add client capabilities for Neovim ``v0.9.1`` diff --git a/lib/pytest-lsp/changes/89.capability.rst b/lib/pytest-lsp/changes/89.capability.rst new file mode 100644 index 0000000..32b6700 --- /dev/null +++ b/lib/pytest-lsp/changes/89.capability.rst @@ -0,0 +1 @@ +Add client capabilities for Neovim versions ``v0.7.0`` and ``v0.8.0`` diff --git a/lib/pytest-lsp/pyproject.toml b/lib/pytest-lsp/pyproject.toml index c48ca36..da51c6d 100644 --- a/lib/pytest-lsp/pyproject.toml +++ b/lib/pytest-lsp/pyproject.toml @@ -67,6 +67,7 @@ underlines = ["-", "^", "\""] type = [ { name = "Features", directory = "feature", showcontent = true }, { name = "Enhancements", directory = "enhancement", showcontent = true }, + { name = "Client Capabilities", directory = "capability", showcontent = true }, { name = "Fixes", directory = "fix", showcontent = true }, { name = "Docs", directory = "doc", showcontent = true }, { name = "Breaking Changes", directory = "breaking", showcontent = true }, From 2b8a34849b7b852d4637a33009b03fc9305538a0 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 19:21:10 +0100 Subject: [PATCH 21/50] lsp-devtools: Add test case --- .../tests/record/test_formatters.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/lsp-devtools/tests/record/test_formatters.py b/lib/lsp-devtools/tests/record/test_formatters.py index c6f7066..1f38e6d 100644 --- a/lib/lsp-devtools/tests/record/test_formatters.py +++ b/lib/lsp-devtools/tests/record/test_formatters.py @@ -126,6 +126,24 @@ }, "- one\n- two", ), + ( + '{{"clientInfo": {.params.clientInfo}, ' + '"capabilities": {.params.capabilities}}}', + { + "params": { + "clientInfo": {"name": "Client", "version": "1.0"}, + "capabilities": {"workspace": {"symbol": True}}, + } + }, + '{"clientInfo": {\n' + ' "name": "Client",\n' + ' "version": "1.0"\n' + '}, "capabilities": {\n' + ' "workspace": {\n' + ' "symbol": true\n' + " }\n" + "}}", + ), ], ) def test_format_string(pattern: str, message: dict, expected: str): From dd83bc880ee58bad4a27cc322a2ccf0688efffc6 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 19:21:29 +0100 Subject: [PATCH 22/50] docs: Update guide on contributing client capabilities --- docs/lsp-devtools/guide/record-command.rst | 8 +--- lib/pytest-lsp/pytest_lsp/clients/README.md | 43 ++++++++++++++++----- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/docs/lsp-devtools/guide/record-command.rst b/docs/lsp-devtools/guide/record-command.rst index b195ced..d0dece1 100644 --- a/docs/lsp-devtools/guide/record-command.rst +++ b/docs/lsp-devtools/guide/record-command.rst @@ -27,15 +27,11 @@ Here are some example usages of the ``record`` command that you may find useful. **Capture the client's capabilities** -The following command will only capture and show the ``ClientCapabilities`` sent during the ``initialize`` request - useful for :ref:`adding clients to pytest-lsp `! 😉 +The following command will save to a JSON file only the client's info and :class:`pygls:lsprotocol.types.ClientCapabilities` sent during the ``initialize`` request - useful for :ref:`adding clients to pytest-lsp `! 😉 :: - lsp-devtools record -f "{.params.clientInfo.name} v{.params.clientInfo.version}\\n{.params.capabilities}" - -.. figure:: /images/record-client-capabilities.svg - :figclass: scrollable-svg - + lsp-devtools record -f '{{"clientInfo": {.params.clientInfo}, "capabilities": {.params.capabilities}}}' --to-file _v.json **Format and show any window/logMessages** diff --git a/lib/pytest-lsp/pytest_lsp/clients/README.md b/lib/pytest-lsp/pytest_lsp/clients/README.md index c7f29c9..119aa9c 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/README.md +++ b/lib/pytest-lsp/pytest_lsp/clients/README.md @@ -1,16 +1,41 @@ # Clients -This folder contains recorded `ClientCapabilities` responses from various language clients at various versions. +This folder contains captured [`ClientCapabilities`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#clientCapabilities) responses from various language clients at various versions. -These snapshots is how the `pytest-lsp` plugin is able to simulate different language clients when testing a language server. +These snapshots are how `pytest-lsp` plugin is able to impersonate different language clients when testing a server. +They also power the [Client Capability Index](https://lsp-devtools.readthedocs.io/en/latest/#client-capability-index) section of the documentation. -## Adding new clients/versions +Each filename follows the `_v.json` naming convention and contain the following fields of an [`InitializeParams`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initializeParams) object. -Adding support for a new client requires the client's `ClientCapabilities` response being captured in a JSON file and stored in this folder. -The simplest way to generate the required JSON file is to use the `lsp-devtools capabilities` command. +```json +{ + "clientInfo": { + "name": "Client Name", + "version": "1.2.3" + }, + "capabilities": { ... } +} +``` -1. Configure the language client to call the `lsp-devtools capabilities` command as if it were a language server. -1. Run the language client as configured to generate a `ClientCapabilites` response. -1. A file called `_v.json` should appear in you working directory, copy-paste it into this folder. +## Adding new clients and versions -New versions of a client should only be added if there is a noticable difference in the `ClientCapabilities` response when compared to previous versions.. +### Neovim + +Adding new neovim versions has been semi-automated through a [Github Actions workflow](https://github.com/swyddfa/lsp-devtools/blob/develop/.github/workflows/capabilities-nvim.yml) + +### Other Clients + +This can be done with `lsp-devtools` command. + +1. Configure the language client to invoke a language server [wrapped with the lsp-devtools agent](https://lsp-devtools.readthedocs.io/en/latest/lsp-devtools/guide/getting-started.html#configuring-your-client). + +1. In a separate terminal, use the following `lsp-devtools` command to record the necessary information to a JSON file + ``` + lsp-devtools record -f '{{"clientInfo": {.params.clientInfo}, "capabilities": {.params.capabilities}}}' --to-file _v.json + ``` + +1. Run the language server via the client to generate the necessary data, once the server is ready to use you should be able to close the client. + +1. The `lsp-devtools record` command should have exited with a file called `_v.json` saved to your working directory. + +1. Open a pull request adding the file to this folder! From 18a8fb206cb0114a9d56dad7b64811a0bd03ec4a Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 21 Oct 2023 19:56:42 +0100 Subject: [PATCH 23/50] pre-commit: Add hook to check client capabilities - Ensure that the data can be parsed as `InitializeParams` - Ensure that the JSON files are formatted consistently --- .pre-commit-config.yaml | 11 + .../pytest_lsp/clients/neovim_v0.6.1.json | 2 +- .../pytest_lsp/clients/neovim_v0.7.0.json | 456 +++++++------- .../pytest_lsp/clients/neovim_v0.8.0.json | 460 +++++++------- .../pytest_lsp/clients/neovim_v0.9.1.json | 568 +++++++++--------- .../clients/visual_studio_code_v1.65.2.json | 2 +- scripts/check_capabilities.py | 33 + 7 files changed, 789 insertions(+), 743 deletions(-) create mode 100644 scripts/check_capabilities.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9265d8b..4493b7e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,6 +6,7 @@ repos: hooks: - id: check-yaml - id: end-of-file-fixer + exclude: 'lib/pytest-lsp/pytest_lsp/clients/.*\.json' - id: trailing-whitespace - repo: https://github.com/psf/black @@ -62,3 +63,13 @@ repos: - textual - websockets files: 'lib/lsp-devtools/lsp_devtools/.*\.py' + +- repo: local + hooks: + - id: check-capabilities + name: check-capabilities + language: python + additional_dependencies: + - lsprotocol + files: 'lib/pytest-lsp/pytest_lsp/clients/.*\.json' + entry: python scripts/check_capabilities.py diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json index 61c79b2..4970156 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.6.1.json @@ -228,4 +228,4 @@ } } } -} +} \ No newline at end of file diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json index 593f24a..bacf117 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.7.0.json @@ -1,234 +1,234 @@ { - "capabilities": { - "window": { - "workDoneProgress": true, - "showMessage": { - "messageActionItem": { - "additionalPropertiesSupport": false - } - }, - "showDocument": { - "support": false - } - }, - "textDocument": { - "documentSymbol": { - "hierarchicalDocumentSymbolSupport": true, - "dynamicRegistration": false, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] - } - }, - "rename": { - "prepareSupport": true, - "dynamicRegistration": false - }, - "references": { - "dynamicRegistration": false - }, - "documentHighlight": { - "dynamicRegistration": false - }, - "hover": { - "contentFormat": [ - "markdown", - "plaintext" - ], - "dynamicRegistration": false - }, - "implementation": { - "linkSupport": true - }, - "synchronization": { - "didSave": true, - "dynamicRegistration": false, - "willSave": false, - "willSaveWaitUntil": false - }, - "declaration": { - "linkSupport": true - }, - "publishDiagnostics": { - "tagSupport": { - "valueSet": [ - 1, - 2 - ] - }, - "relatedInformation": true - }, - "completion": { - "completionItemKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25 - ] - }, - "dynamicRegistration": false, - "contextSupport": false, - "completionItem": { - "documentationFormat": [ - "markdown", - "plaintext" - ], - "snippetSupport": false, - "commitCharactersSupport": false, - "preselectSupport": false, - "deprecatedSupport": false - } - }, - "definition": { - "linkSupport": true - }, - "typeDefinition": { - "linkSupport": true - }, - "codeAction": { - "resolveSupport": { - "properties": [ - "edit" - ] - }, - "dynamicRegistration": false, - "codeActionLiteralSupport": { - "codeActionKind": { - "valueSet": [ - "", - "Empty", - "QuickFix", - "Refactor", - "RefactorExtract", - "RefactorInline", - "RefactorRewrite", - "Source", - "SourceOrganizeImports", - "quickfix", - "refactor", - "refactor.extract", - "refactor.inline", - "refactor.rewrite", - "source", - "source.organizeImports" - ] - } - }, - "dataSupport": true - }, - "signatureHelp": { - "signatureInformation": { - "documentationFormat": [ - "markdown", - "plaintext" - ], - "activeParameterSupport": true, - "parameterInformation": { - "labelOffsetSupport": true - } - }, - "dynamicRegistration": false - } + "capabilities": { + "window": { + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": false + } + }, + "showDocument": { + "support": false + } + }, + "textDocument": { + "documentSymbol": { + "hierarchicalDocumentSymbolSupport": true, + "dynamicRegistration": false, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + } + }, + "rename": { + "prepareSupport": true, + "dynamicRegistration": false + }, + "references": { + "dynamicRegistration": false + }, + "documentHighlight": { + "dynamicRegistration": false + }, + "hover": { + "contentFormat": [ + "markdown", + "plaintext" + ], + "dynamicRegistration": false + }, + "implementation": { + "linkSupport": true + }, + "synchronization": { + "didSave": true, + "dynamicRegistration": false, + "willSave": false, + "willSaveWaitUntil": false + }, + "declaration": { + "linkSupport": true + }, + "publishDiagnostics": { + "tagSupport": { + "valueSet": [ + 1, + 2 + ] }, - "callHierarchy": { - "dynamicRegistration": false + "relatedInformation": true + }, + "completion": { + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] }, - "workspace": { - "workspaceEdit": { - "resourceOperations": [ - "rename", - "create", - "delete" - ] - }, - "applyEdit": true, - "symbol": { - "dynamicRegistration": false, - "hierarchicalWorkspaceSymbolSupport": true, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] - } - }, - "workspaceFolders": true + "dynamicRegistration": false, + "contextSupport": false, + "completionItem": { + "documentationFormat": [ + "markdown", + "plaintext" + ], + "snippetSupport": false, + "commitCharactersSupport": false, + "preselectSupport": false, + "deprecatedSupport": false } + }, + "definition": { + "linkSupport": true + }, + "typeDefinition": { + "linkSupport": true + }, + "codeAction": { + "resolveSupport": { + "properties": [ + "edit" + ] + }, + "dynamicRegistration": false, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "Empty", + "QuickFix", + "Refactor", + "RefactorExtract", + "RefactorInline", + "RefactorRewrite", + "Source", + "SourceOrganizeImports", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + }, + "dataSupport": true + }, + "signatureHelp": { + "signatureInformation": { + "documentationFormat": [ + "markdown", + "plaintext" + ], + "activeParameterSupport": true, + "parameterInformation": { + "labelOffsetSupport": true + } + }, + "dynamicRegistration": false + } }, - "clientInfo": { - "name": "Neovim", - "version": "0.7.0" + "callHierarchy": { + "dynamicRegistration": false + }, + "workspace": { + "workspaceEdit": { + "resourceOperations": [ + "rename", + "create", + "delete" + ] + }, + "applyEdit": true, + "symbol": { + "dynamicRegistration": false, + "hierarchicalWorkspaceSymbolSupport": true, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + } + }, + "workspaceFolders": true } -} + }, + "clientInfo": { + "name": "Neovim", + "version": "0.7.0" + } +} \ No newline at end of file diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json index 62ff6ba..3d0e10b 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.8.0.json @@ -1,236 +1,236 @@ { - "clientInfo": { - "name": "Neovim", - "version": "0.8.0" + "clientInfo": { + "name": "Neovim", + "version": "0.8.0" + }, + "capabilities": { + "workspace": { + "configuration": true, + "applyEdit": true, + "workspaceEdit": { + "resourceOperations": [ + "rename", + "create", + "delete" + ] + }, + "workspaceFolders": true, + "symbol": { + "dynamicRegistration": false, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "hierarchicalWorkspaceSymbolSupport": true + } + }, + "window": { + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": false + } + }, + "showDocument": { + "support": false + } }, - "capabilities": { - "workspace": { - "configuration": true, - "applyEdit": true, - "workspaceEdit": { - "resourceOperations": [ - "rename", - "create", - "delete" - ] - }, - "workspaceFolders": true, - "symbol": { - "dynamicRegistration": false, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] - }, - "hierarchicalWorkspaceSymbolSupport": true - } + "callHierarchy": { + "dynamicRegistration": false + }, + "textDocument": { + "synchronization": { + "didSave": true, + "dynamicRegistration": false, + "willSave": false, + "willSaveWaitUntil": false + }, + "documentSymbol": { + "dynamicRegistration": false, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] }, - "window": { - "workDoneProgress": true, - "showMessage": { - "messageActionItem": { - "additionalPropertiesSupport": false - } - }, - "showDocument": { - "support": false - } + "hierarchicalDocumentSymbolSupport": true + }, + "declaration": { + "linkSupport": true + }, + "hover": { + "contentFormat": [ + "markdown", + "plaintext" + ], + "dynamicRegistration": false + }, + "definition": { + "linkSupport": true + }, + "implementation": { + "linkSupport": true + }, + "typeDefinition": { + "linkSupport": true + }, + "publishDiagnostics": { + "relatedInformation": true, + "tagSupport": { + "valueSet": [ + 1, + 2 + ] + } + }, + "signatureHelp": { + "signatureInformation": { + "activeParameterSupport": true, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "parameterInformation": { + "labelOffsetSupport": true + } }, - "callHierarchy": { - "dynamicRegistration": false + "dynamicRegistration": false + }, + "rename": { + "prepareSupport": true, + "dynamicRegistration": false + }, + "completion": { + "dynamicRegistration": false, + "completionItem": { + "deprecatedSupport": false, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "commitCharactersSupport": false, + "snippetSupport": false, + "preselectSupport": false }, - "textDocument": { - "synchronization": { - "didSave": true, - "dynamicRegistration": false, - "willSave": false, - "willSaveWaitUntil": false - }, - "documentSymbol": { - "dynamicRegistration": false, - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] - }, - "hierarchicalDocumentSymbolSupport": true - }, - "declaration": { - "linkSupport": true - }, - "hover": { - "contentFormat": [ - "markdown", - "plaintext" - ], - "dynamicRegistration": false - }, - "definition": { - "linkSupport": true - }, - "implementation": { - "linkSupport": true - }, - "typeDefinition": { - "linkSupport": true - }, - "publishDiagnostics": { - "relatedInformation": true, - "tagSupport": { - "valueSet": [ - 1, - 2 - ] - } - }, - "signatureHelp": { - "signatureInformation": { - "activeParameterSupport": true, - "documentationFormat": [ - "markdown", - "plaintext" - ], - "parameterInformation": { - "labelOffsetSupport": true - } - }, - "dynamicRegistration": false - }, - "rename": { - "prepareSupport": true, - "dynamicRegistration": false - }, - "completion": { - "dynamicRegistration": false, - "completionItem": { - "deprecatedSupport": false, - "documentationFormat": [ - "markdown", - "plaintext" - ], - "commitCharactersSupport": false, - "snippetSupport": false, - "preselectSupport": false - }, - "completionItemKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25 - ] - }, - "contextSupport": false - }, - "documentHighlight": { - "dynamicRegistration": false - }, - "codeAction": { - "dynamicRegistration": false, - "dataSupport": true, - "resolveSupport": { - "properties": [ - "edit" - ] - }, - "codeActionLiteralSupport": { - "codeActionKind": { - "valueSet": [ - "", - "Empty", - "QuickFix", - "Refactor", - "RefactorExtract", - "RefactorInline", - "RefactorRewrite", - "Source", - "SourceOrganizeImports", - "quickfix", - "refactor", - "refactor.extract", - "refactor.inline", - "refactor.rewrite", - "source", - "source.organizeImports" - ] - } - }, - "isPreferredSupport": true - }, - "references": { - "dynamicRegistration": false - } - } + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + }, + "contextSupport": false + }, + "documentHighlight": { + "dynamicRegistration": false + }, + "codeAction": { + "dynamicRegistration": false, + "dataSupport": true, + "resolveSupport": { + "properties": [ + "edit" + ] + }, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "Empty", + "QuickFix", + "Refactor", + "RefactorExtract", + "RefactorInline", + "RefactorRewrite", + "Source", + "SourceOrganizeImports", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + }, + "isPreferredSupport": true + }, + "references": { + "dynamicRegistration": false + } } -} + } +} \ No newline at end of file diff --git a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json index a0088c3..b07184b 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json +++ b/lib/pytest-lsp/pytest_lsp/clients/neovim_v0.9.1.json @@ -1,288 +1,290 @@ { - "clientInfo": { - "version": "0.9.1", - "name": "Neovim" - }, - "capabilities": { - "textDocument": { - "declaration": { - "linkSupport": true - }, - "synchronization": { - "didSave": true, - "willSave": true, - "dynamicRegistration": false, - "willSaveWaitUntil": true - }, - "callHierarchy": { - "dynamicRegistration": false - }, - "codeAction": { - "isPreferredSupport": true, - "dataSupport": true, - "resolveSupport": { - "properties": [ - "edit" - ] - }, - "codeActionLiteralSupport": { - "codeActionKind": { - "valueSet": [ - "", - "quickfix", - "refactor", - "refactor.extract", - "refactor.inline", - "refactor.rewrite", - "source", - "source.organizeImports" - ] - } - }, - "dynamicRegistration": false - }, - "publishDiagnostics": { - "tagSupport": { - "valueSet": [ - 1, - 2 - ] - }, - "relatedInformation": true - }, - "rename": { - "dynamicRegistration": false, - "prepareSupport": true - }, - "implementation": { - "linkSupport": true - }, - "typeDefinition": { - "linkSupport": true - }, - "documentSymbol": { - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] - }, - "dynamicRegistration": false, - "hierarchicalDocumentSymbolSupport": true - }, - "signatureHelp": { - "dynamicRegistration": false, - "signatureInformation": { - "parameterInformation": { - "labelOffsetSupport": true - }, - "documentationFormat": [ - "markdown", - "plaintext" - ], - "activeParameterSupport": true - } - }, - "hover": { - "dynamicRegistration": false, - "contentFormat": [ - "markdown", - "plaintext" - ] - }, - "definition": { - "linkSupport": true - }, - "completion": { - "contextSupport": false, - "completionItem": { - "preselectSupport": false, - "deprecatedSupport": false, - "documentationFormat": [ - "markdown", - "plaintext" - ], - "snippetSupport": false, - "commitCharactersSupport": false - }, - "dynamicRegistration": false, - "completionItemKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25 - ] - } - }, - "semanticTokens": { - "augmentsSyntaxTokens": true, - "requests": { - "range": false, - "full": { - "delta": true - } - }, - "tokenModifiers": [ - "declaration", - "definition", - "readonly", - "static", - "deprecated", - "abstract", - "async", - "modification", - "documentation", - "defaultLibrary" - ], - "formats": [ - "relative" - ], - "dynamicRegistration": false, - "tokenTypes": [ - "namespace", - "type", - "class", - "enum", - "interface", - "struct", - "typeParameter", - "parameter", - "variable", - "property", - "enumMember", - "event", - "function", - "method", - "macro", - "keyword", - "modifier", - "comment", - "string", - "number", - "regexp", - "operator", - "decorator" - ], - "overlappingTokenSupport": true, - "multilineTokenSupport": false, - "serverCancelSupport": false - }, - "references": { - "dynamicRegistration": false - }, - "documentHighlight": { - "dynamicRegistration": false - } + "clientInfo": { + "version": "0.9.1", + "name": "Neovim" + }, + "capabilities": { + "textDocument": { + "declaration": { + "linkSupport": true + }, + "synchronization": { + "didSave": true, + "willSave": true, + "dynamicRegistration": false, + "willSaveWaitUntil": true + }, + "callHierarchy": [ + { + "dynamicRegistration": false + } + ], + "codeAction": { + "isPreferredSupport": true, + "dataSupport": true, + "resolveSupport": { + "properties": [ + "edit" + ] + }, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } }, - "window": { - "showDocument": { - "support": true - }, - "workDoneProgress": true, - "showMessage": { - "messageActionItem": { - "additionalPropertiesSupport": false - } - } + "dynamicRegistration": false + }, + "publishDiagnostics": { + "tagSupport": { + "valueSet": [ + 1, + 2 + ] + }, + "relatedInformation": true + }, + "rename": { + "dynamicRegistration": false, + "prepareSupport": true + }, + "implementation": { + "linkSupport": true + }, + "typeDefinition": { + "linkSupport": true + }, + "documentSymbol": { + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "dynamicRegistration": false, + "hierarchicalDocumentSymbolSupport": true + }, + "signatureHelp": { + "dynamicRegistration": false, + "signatureInformation": { + "parameterInformation": { + "labelOffsetSupport": true + }, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "activeParameterSupport": true + } + }, + "hover": { + "dynamicRegistration": false, + "contentFormat": [ + "markdown", + "plaintext" + ] + }, + "definition": { + "linkSupport": true + }, + "completion": { + "contextSupport": false, + "completionItem": { + "preselectSupport": false, + "deprecatedSupport": false, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "snippetSupport": false, + "commitCharactersSupport": false }, - "workspace": { - "workspaceFolders": true, - "configuration": true, - "applyEdit": true, - "workspaceEdit": { - "resourceOperations": [ - "rename", - "create", - "delete" - ] - }, - "semanticTokens": { - "refreshSupport": true - }, - "symbol": { - "symbolKind": { - "valueSet": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26 - ] - }, - "dynamicRegistration": false, - "hierarchicalWorkspaceSymbolSupport": true - }, - "didChangeWatchedFiles": { - "dynamicRegistration": false, - "relativePatternSupport": true - } + "dynamicRegistration": false, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] } + }, + "semanticTokens": { + "augmentsSyntaxTokens": true, + "requests": { + "range": false, + "full": { + "delta": true + } + }, + "tokenModifiers": [ + "declaration", + "definition", + "readonly", + "static", + "deprecated", + "abstract", + "async", + "modification", + "documentation", + "defaultLibrary" + ], + "formats": [ + "relative" + ], + "dynamicRegistration": false, + "tokenTypes": [ + "namespace", + "type", + "class", + "enum", + "interface", + "struct", + "typeParameter", + "parameter", + "variable", + "property", + "enumMember", + "event", + "function", + "method", + "macro", + "keyword", + "modifier", + "comment", + "string", + "number", + "regexp", + "operator", + "decorator" + ], + "overlappingTokenSupport": true, + "multilineTokenSupport": false, + "serverCancelSupport": false + }, + "references": { + "dynamicRegistration": false + }, + "documentHighlight": { + "dynamicRegistration": false + } + }, + "window": { + "showDocument": { + "support": true + }, + "workDoneProgress": true, + "showMessage": { + "messageActionItem": { + "additionalPropertiesSupport": false + } + } + }, + "workspace": { + "workspaceFolders": true, + "configuration": true, + "applyEdit": true, + "workspaceEdit": { + "resourceOperations": [ + "rename", + "create", + "delete" + ] + }, + "semanticTokens": { + "refreshSupport": true + }, + "symbol": { + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26 + ] + }, + "dynamicRegistration": false, + "hierarchicalWorkspaceSymbolSupport": true + }, + "didChangeWatchedFiles": { + "dynamicRegistration": false, + "relativePatternSupport": true + } } -} + } +} \ No newline at end of file diff --git a/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json b/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json index 9c09b2b..658b004 100644 --- a/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json +++ b/lib/pytest-lsp/pytest_lsp/clients/visual_studio_code_v1.65.2.json @@ -386,4 +386,4 @@ } } } -} +} \ No newline at end of file diff --git a/scripts/check_capabilities.py b/scripts/check_capabilities.py new file mode 100644 index 0000000..5cccde7 --- /dev/null +++ b/scripts/check_capabilities.py @@ -0,0 +1,33 @@ +import json +import pathlib +import sys + +from lsprotocol import types +from lsprotocol.converters import get_converter + + +def check(filepath: pathlib.Path, converter): + obj = json.loads(filepath.read_text()) + + try: + converter.structure(obj, types.InitializeParams) + except Exception as e: + print(f"{filepath.name}: {e}") + return 1 + + filepath.write_text(json.dumps(obj, indent=2)) + return 0 + + +def main(files: list[str]): + converter = get_converter() + + total = 0 + for filename in files: + total += check(pathlib.Path(filename), converter) + + return total + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) From a2a2f47194ed993e0fe4aebff55d302593810521 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 23 Oct 2023 19:53:46 +0100 Subject: [PATCH 24/50] pytest-lsp: Add `workspace/configuration` support to the client --- lib/pytest-lsp/changes/90.feature.rst | 1 + lib/pytest-lsp/pytest_lsp/client.py | 99 +++++++++++++++++- lib/pytest-lsp/tests/test_client.py | 139 ++++++++++++++++++++++++++ 3 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 lib/pytest-lsp/changes/90.feature.rst diff --git a/lib/pytest-lsp/changes/90.feature.rst b/lib/pytest-lsp/changes/90.feature.rst new file mode 100644 index 0000000..c0e5396 --- /dev/null +++ b/lib/pytest-lsp/changes/90.feature.rst @@ -0,0 +1 @@ +The test ``LanguageClient`` now supports ``workspace/configuration`` requests diff --git a/lib/pytest-lsp/pytest_lsp/client.py b/lib/pytest-lsp/pytest_lsp/client.py index e2de7f0..042cd66 100644 --- a/lib/pytest-lsp/pytest_lsp/client.py +++ b/lib/pytest-lsp/pytest_lsp/client.py @@ -6,6 +6,7 @@ import sys import traceback import typing +from typing import Any from typing import Dict from typing import List from typing import Optional @@ -36,7 +37,7 @@ class LanguageClient(BaseLanguageClient): protocol: LanguageClientProtocol - def __init__(self, *args, **kwargs): + def __init__(self, *args, configuration: Optional[Dict[str, Any]] = None, **kwargs): if "protocol_cls" not in kwargs: kwargs["protocol_cls"] = LanguageClientProtocol @@ -61,6 +62,13 @@ def __init__(self, *args, **kwargs): self.error: Optional[Exception] = None """Indicates if the client encountered an error.""" + config = (configuration or {"": {}}).copy() + if "" not in config: + config[""] = {} + + self._configuration: Dict[str, Dict[str, Any]] = config + """Holds ``workspace/configuration`` values.""" + self._setup_log_index = 0 """Used to keep track of which log messages occurred during startup.""" @@ -101,6 +109,88 @@ def report_server_error( if self._stop_event: self._stop_event.set() + def get_configuration( + self, *, section: Optional[str] = None, scope_uri: Optional[str] = None + ) -> Optional[Any]: + """Get a configuration value. + + Parameters + ---------- + section + The optional section name to retrieve. + If ``None`` the top level configuration object for the requested scope will + be returned + + scope_uri + The scope at which to set the configuration. + If ``None``, this will default to the global scope. + + Returns + ------- + Optional[Any] + The requested configuration value or ``None`` if not found. + """ + section = section or "" + scope = scope_uri or "" + + # Find the longest prefix of ``scope``. The empty string is a prefix of all + # strings so there will always be at least one match + candidates = [c for c in self._configuration.keys() if scope.startswith(c)] + selected = sorted(candidates, key=len, reverse=True)[0] + + if (item := self._configuration.get(selected, None)) is None: + return None + + if section == "": + return item + + for segment in section.split("."): + if not hasattr(item, "get"): + return None + + if (item := item.get(segment, None)) is None: + return None + + return item + + def set_configuration( + self, + item: Any, + *, + section: Optional[str] = None, + scope_uri: Optional[str] = None, + ): + """Set a configuration value. + + Parameters + ---------- + item + The value to set + + section + The optional section name to set. + If ``None`` the top level configuration object will be overriden with + ``item``. + + scope_uri + The scope at which to set the configuration. + If ``None``, this will default to the global scope. + """ + section = section or "" + scope = scope_uri or "" + + if section == "": + self._configuration[scope] = item + return + + config = self._configuration.setdefault(scope, {}) + *parents, name = section.split(".") + + for segment in parents: + config = config.setdefault(segment, {}) + + config[name] = item + async def initialize_session( self, params: types.InitializeParams ) -> types.InitializeResult: @@ -180,6 +270,13 @@ def make_test_lsp_client() -> LanguageClient: converter_factory=default_converter, ) + @client.feature(types.WORKSPACE_CONFIGURATION) + def configuration(client: LanguageClient, params: types.ConfigurationParams): + return [ + client.get_configuration(section=item.section, scope_uri=item.scope_uri) + for item in params.items + ] + @client.feature(types.TEXT_DOCUMENT_PUBLISH_DIAGNOSTICS) def publish_diagnostics( client: LanguageClient, params: types.PublishDiagnosticsParams diff --git a/lib/pytest-lsp/tests/test_client.py b/lib/pytest-lsp/tests/test_client.py index 5ba13b4..8d6beba 100644 --- a/lib/pytest-lsp/tests/test_client.py +++ b/lib/pytest-lsp/tests/test_client.py @@ -2,11 +2,15 @@ import json import pathlib import sys +from typing import Any +from typing import Dict +from typing import Optional import pygls.uris as uri import pytest import pytest_lsp +from pytest_lsp import LanguageClient @pytest.mark.parametrize( @@ -113,3 +117,138 @@ async def test_capabilities(client): results = pytester.runpytest("-vv") results.assert_outcomes(passed=1) + + +@pytest.mark.parametrize( + "config,section,scope,expected", + [ + ({"": 12}, None, None, 12), + ({"": 12}, "example.section", None, None), + ({"": 12}, None, "file://path/to/workspace/file.txt", 12), + ({"": {"example": {"section": 12}}}, "example", None, {"section": 12}), + ({"": {"example": {"section": 12}}}, "example.section", None, 12), + ( + {"": {"example": {"section": 12}}}, + "example.section", + "file://path/to/workspace/file.txt", + 12, + ), + ( + { + "": {"example": {"section": 12}}, + "file://path/to/workspace": {"example": {"section": 32}}, + }, + "example.section", + "file://path/to/workspace/file.txt", + 32, + ), + # To keep things simple, we will not try to fallback to more general scopes. + ( + { + "": {"example": {"section": 12}}, + "file://path/to/workspace": {"example": 32}, + }, + "example.section", + "file://path/to/workspace/file.txt", + None, + ), + ], +) +def test_get_configuration( + config: Dict[str, Any], section: Optional[str], scope: Optional[str], expected: Any +): + """Ensure that we can get a client's configuration correctly. + + Parameters + ---------- + config + The client's configuration + + section + The section name to retrieve + + scope + The scope to retrieve + + expected + The expected result + """ + + client = LanguageClient(configuration=config) + assert client.get_configuration(section=section, scope_uri=scope) == expected + + +@pytest.mark.parametrize( + "item,section,scope,expected", + [ + (12, None, None, {"": 12}), + ( + 12, + None, + "file://path/to/workspace", + {"": {}, "file://path/to/workspace": 12}, + ), + (12, "example", None, {"": {"example": 12}}), + ( + 12, + "example.config.section", + None, + {"": {"example": {"config": {"section": 12}}}}, + ), + ], +) +def test_set_configuration( + item: Any, section: Optional[str], scope: Optional[str], expected: Dict[str, Any] +): + """Ensure that we can set the client's configuration correctly. + + Parameters + ---------- + item + The value to set + + section + The configuration section to set + + scope + The scope at which to set the configuration + + expected + The expected result + """ + client = LanguageClient() + client.set_configuration(item, section=section, scope_uri=scope) + + assert client._configuration == expected + + +def test_set_configuration_equivalent_methods(): + """Ensure that setting the configuration using alternate, but equivalent methods + yields the same result.""" + + client_one = LanguageClient() + client_two = LanguageClient() + + config = { + "example": { + "section": 12, + "value": "test", + "nested": {"section": 34}, + }, + } + client_one.set_configuration(config) + + client_two.set_configuration(12, section="example.section") + client_two.set_configuration("test", section="example.value") + client_two.set_configuration(34, section="example.nested.section") + + expected = { + "": { + "example": { + "section": 12, + "value": "test", + "nested": {"section": 34}, + }, + }, + } + assert client_one._configuration == expected == client_two._configuration From 67838e91bcf25e38316afd700c4e45ba14565e03 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 23 Oct 2023 19:55:06 +0100 Subject: [PATCH 25/50] pytest-lsp: Cleanup unecessary warnings --- docs/pytest-lsp/guide/troubleshooting.rst | 6 ------ lib/pytest-lsp/tests/test_examples.py | 6 +----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/docs/pytest-lsp/guide/troubleshooting.rst b/docs/pytest-lsp/guide/troubleshooting.rst index bd93473..e550e33 100644 --- a/docs/pytest-lsp/guide/troubleshooting.rst +++ b/docs/pytest-lsp/guide/troubleshooting.rst @@ -110,9 +110,3 @@ Depending on the version of ``pygls`` (the LSP implementation used by ``pytest-l =========================== 1 passed, 1 warning in 0.64s ============================= This is a known issue in ``pygls v1.0.2`` and older, upgrading your ``pygls`` version to ``1.1.0`` or newer should resolve the issue. - -.. note:: - - While this issue has been `fixed `_ upstream, it is not yet generally available. - However, the warning itself is fairly mild - ``pytest-lsp``/``pygls`` are not cleaning the event loop up correctly but are otherwise working as expected. - It should be safe to ignore this while waiting for the fix to become available. diff --git a/lib/pytest-lsp/tests/test_examples.py b/lib/pytest-lsp/tests/test_examples.py index d493e3d..32f47d8 100644 --- a/lib/pytest-lsp/tests/test_examples.py +++ b/lib/pytest-lsp/tests/test_examples.py @@ -48,9 +48,7 @@ def test_client_capabilities(pytester: pytest.Pytester): setup_test(pytester, "client-capabilities") - results = pytester.runpytest( - "-W", "ignore::DeprecationWarning:pytest_asyncio.plugin" - ) + results = pytester.runpytest() results.assert_outcomes(passed=1, warnings=1) message = "*LspSpecificationWarning: Client does not support snippets." @@ -79,8 +77,6 @@ def test_client_capabilities_ignore(pytester: pytest.Pytester): results = pytester.runpytest( "-W", "ignore::pytest_lsp.LspSpecificationWarning", - "-W", - "ignore::DeprecationWarning:pytest_asyncio.plugin", ) results.assert_outcomes(passed=1, warnings=0) From 60016ee7f0faf919b63f44e8ea7a52d4213f39d6 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 23 Oct 2023 19:59:15 +0100 Subject: [PATCH 26/50] pytest-lsp: Add spec compliance check for `workspace/configuration` The `LanguageClientProtocol` class is now also able to perform complicance checks on incoming requests from the server under test. The first check implemented is making sure that the client has support for `workspace/configuration` requests. --- lib/pytest-lsp/pytest_lsp/checks.py | 123 ++++++++++++++++++++------ lib/pytest-lsp/pytest_lsp/protocol.py | 95 ++++++++++++++++---- lib/pytest-lsp/tests/test_checks.py | 43 +++++++++ 3 files changed, 218 insertions(+), 43 deletions(-) create mode 100644 lib/pytest-lsp/tests/test_checks.py diff --git a/lib/pytest-lsp/pytest_lsp/checks.py b/lib/pytest-lsp/pytest_lsp/checks.py index c468b02..08d996a 100644 --- a/lib/pytest-lsp/pytest_lsp/checks.py +++ b/lib/pytest-lsp/pytest_lsp/checks.py @@ -18,19 +18,14 @@ from typing import Set from typing import Union -from lsprotocol.types import COMPLETION_ITEM_RESOLVE -from lsprotocol.types import TEXT_DOCUMENT_COMPLETION -from lsprotocol.types import TEXT_DOCUMENT_DOCUMENT_LINK -from lsprotocol.types import ClientCapabilities -from lsprotocol.types import CompletionItem -from lsprotocol.types import CompletionList -from lsprotocol.types import DocumentLink -from lsprotocol.types import InsertTextFormat -from lsprotocol.types import MarkupContent +from lsprotocol import types from pygls.capabilities import get_capability logger = logging.getLogger(__name__) -ResultChecker = Callable[[ClientCapabilities, Any], None] +ParamsChecker = Callable[[types.ClientCapabilities, Any], None] +ResultChecker = Callable[[types.ClientCapabilities, Any], None] + +PARAMS_CHECKS: Dict[str, ParamsChecker] = {} RESULT_CHECKS: Dict[str, ResultChecker] = {} @@ -38,29 +33,56 @@ class LspSpecificationWarning(UserWarning): """Warning raised when encountering results that fall outside the spec.""" -def check_result_for(maybe_fn: Optional[ResultChecker] = None, *, method: str): +def check_result_for(*, method: str) -> Callable[[ResultChecker], ResultChecker]: """Define a result check.""" def defcheck(fn: ResultChecker): + if (existing := RESULT_CHECKS.get(method, None)) is not None: + raise ValueError(f"{fn!r} conflicts with existing check {existing!r}") + RESULT_CHECKS[method] = fn return fn - if maybe_fn: - return defcheck(maybe_fn) + return defcheck + + +def check_params_of(*, method: str) -> Callable[[ParamsChecker], ParamsChecker]: + """Define a params check.""" + + def defcheck(fn: ParamsChecker): + if (existing := PARAMS_CHECKS.get(method, None)) is not None: + raise ValueError(f"{fn!r} conflicts with existing check {existing!r}") + + PARAMS_CHECKS[method] = fn + return fn return defcheck def check_result_against_client_capabilities( - capabilities: Optional[ClientCapabilities], method: str, result: Any + capabilities: Optional[types.ClientCapabilities], method: str, result: Any ): - """Check that the given result respects the client's declared capabilities.""" + """Check that the given result respects the client's declared capabilities. + + This will emit an ``LspSpecificationWarning`` if any issues are detected. + + Parameters + ---------- + capabilities + The client's capabilities + + method + The method name to validate the result of + + result + The result to validate + """ if capabilities is None: raise RuntimeError("Client has not been initialized") # Only run checks if the user provided some capabilities for the client. - if capabilities == ClientCapabilities(): + if capabilities == types.ClientCapabilities(): return result_checker = RESULT_CHECKS.get(method, None) @@ -73,8 +95,43 @@ def check_result_against_client_capabilities( warnings.warn(str(e), LspSpecificationWarning, stacklevel=4) +def check_params_against_client_capabilities( + capabilities: Optional[types.ClientCapabilities], method: str, params: Any +): + """Check that the given params respect the client's declared capabilities. + + This will emit an ``LspSpecificationWarning`` if any issues are detected. + + Parameters + ---------- + capabilities + The client's capabilities + + method + The method name to validate the result of + + params + The params to validate + """ + if capabilities is None: + raise RuntimeError("Client has not been initialized") + + # Only run checks if the user provided some capabilities for the client. + if capabilities == types.ClientCapabilities(): + return + + params_checker = PARAMS_CHECKS.get(method, None) + if params_checker is None: + return + + try: + params_checker(capabilities, params) + except AssertionError as e: + warnings.warn(str(e), LspSpecificationWarning, stacklevel=2) + + def check_completion_item( - item: CompletionItem, + item: types.CompletionItem, commit_characters_support: bool, documentation_formats: Set[str], snippet_support: bool, @@ -84,19 +141,19 @@ def check_completion_item( if item.commit_characters: assert commit_characters_support, "Client does not support commit characters" - if isinstance(item.documentation, MarkupContent): + if isinstance(item.documentation, types.MarkupContent): kind = item.documentation.kind message = f"Client does not support documentation format '{kind}'" assert kind in documentation_formats, message - if item.insert_text_format == InsertTextFormat.Snippet: + if item.insert_text_format == types.InsertTextFormat.Snippet: assert snippet_support, "Client does not support snippets." -@check_result_for(method=TEXT_DOCUMENT_COMPLETION) +@check_result_for(method=types.TEXT_DOCUMENT_COMPLETION) def completion_items( - capabilities: ClientCapabilities, - result: Union[CompletionList, List[CompletionItem], None], + capabilities: types.ClientCapabilities, + result: Union[types.CompletionList, List[types.CompletionItem], None], ): """Ensure that the completion items returned from the server are compliant with the spec and the client's declared capabilities.""" @@ -122,7 +179,7 @@ def completion_items( False, ) - if isinstance(result, CompletionList): + if isinstance(result, types.CompletionList): items = result.items else: items = result @@ -136,8 +193,10 @@ def completion_items( ) -@check_result_for(method=COMPLETION_ITEM_RESOLVE) -def completion_item_resolve(capabilities: ClientCapabilities, item: CompletionItem): +@check_result_for(method=types.COMPLETION_ITEM_RESOLVE) +def completion_item_resolve( + capabilities: types.ClientCapabilities, item: types.CompletionItem +): """Ensure that the completion item returned from the server is compliant with the spec and the client's declared capbabilities.""" @@ -167,9 +226,9 @@ def completion_item_resolve(capabilities: ClientCapabilities, item: CompletionIt ) -@check_result_for(method=TEXT_DOCUMENT_DOCUMENT_LINK) +@check_result_for(method=types.TEXT_DOCUMENT_DOCUMENT_LINK) def document_links( - capabilities: ClientCapabilities, result: Optional[List[DocumentLink]] + capabilities: types.ClientCapabilities, result: Optional[List[types.DocumentLink]] ): """Ensure that the document links returned from the server are compliant with the Spec and the client's declared capabilities.""" @@ -184,3 +243,13 @@ def document_links( for item in result: if item.tooltip: assert tooltip_support, "Client does not support tooltips." + + +@check_params_of(method=types.WORKSPACE_CONFIGURATION) +def workspace_configuration( + capabilities: types.ClientCapabilities, + params: types.WorkspaceConfigurationParams, +): + """Ensure that the client has support for ``workspace/configuration`` requests.""" + is_supported = get_capability(capabilities, "workspace.configuration", False) + assert is_supported, "Client does not support 'workspace/configuration'" diff --git a/lib/pytest-lsp/pytest_lsp/protocol.py b/lib/pytest-lsp/pytest_lsp/protocol.py index 24adfb2..e849b9f 100644 --- a/lib/pytest-lsp/pytest_lsp/protocol.py +++ b/lib/pytest-lsp/pytest_lsp/protocol.py @@ -1,44 +1,78 @@ +from __future__ import annotations + import asyncio import logging +import typing from concurrent.futures import Future -from lsprotocol.types import CANCEL_REQUEST -from pygls.exceptions import JsonRpcMethodNotFound from pygls.protocol import LanguageServerProtocol +from .checks import check_params_against_client_capabilities from .checks import check_result_against_client_capabilities +if typing.TYPE_CHECKING: + from .client import LanguageClient + + logger = logging.getLogger(__name__) class LanguageClientProtocol(LanguageServerProtocol): - """An extended protocol class with extra methods that are useful for testing.""" + """An extended protocol class adding functionality useful for testing.""" + + _server: LanguageClient # type: ignore[assignment] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._notification_futures = {} + def _handle_request(self, msg_id, method_name, params): + """Wrap pygls' handle_request implementation. This will + + - Check if the request from the server is compatible with the client's stated + capabilities. + + """ + check_params_against_client_capabilities( + self._server.capabilities, method_name, params + ) + return super()._handle_request(msg_id, method_name, params) + def _handle_notification(self, method_name, params): - if method_name == CANCEL_REQUEST: - self._handle_cancel_notification(params.id) - return + """Wrap pygls' handle_notification implementation. This will + + - Notify a future waiting on the notification, if applicable. + - Check the params to see if they are compatible with the client's stated + capabilities. + + """ future = self._notification_futures.pop(method_name, None) if future: future.set_result(params) - try: - handler = self._get_handler(method_name) - self._execute_notification(handler, params) - except (KeyError, JsonRpcMethodNotFound): - logger.warning("Ignoring notification for unknown method '%s'", method_name) - except Exception: - logger.exception( - "Failed to handle notification '%s': %s", method_name, params - ) + super()._handle_notification(method_name, params) async def send_request_async(self, method, params=None): + """Wrap pygls' ``send_request_async`` implementation. This will + + - Check the result to see if it's compatible with the client's stated + capabilities + + Parameters + ---------- + method + The method name of the request to send + + params + The associated parameters to go with the request + + Returns + ------- + Any + The response's result + """ result = await super().send_request_async(method, params) check_result_against_client_capabilities( self._server.capabilities, method, result # type: ignore @@ -46,7 +80,24 @@ async def send_request_async(self, method, params=None): return result - def wait_for_notification(self, method: str, callback=None): + def wait_for_notification(self, method: str, callback=None) -> Future: + """Wait for a notification message with the given ``method``. + + Parameters + ---------- + method + The method name to wait for + + callback + If given, ``callback`` will be called with the notification message's + ``params`` when recevied + + Returns + ------- + Future + A future that will resolve when the requested notification message is + recevied. + """ future: Future = Future() if callback: @@ -60,5 +111,17 @@ def wrapper(future: Future): return future def wait_for_notification_async(self, method: str): + """Wait for a notification message with the given ``method``. + + Parameters + ---------- + method + The method name to wait for + + Returns + ------- + Any + The notification message's ``params`` + """ future = self.wait_for_notification(method) return asyncio.wrap_future(future) diff --git a/lib/pytest-lsp/tests/test_checks.py b/lib/pytest-lsp/tests/test_checks.py new file mode 100644 index 0000000..3d5608a --- /dev/null +++ b/lib/pytest-lsp/tests/test_checks.py @@ -0,0 +1,43 @@ +from typing import Any + +import pytest +from lsprotocol import types + +from pytest_lsp import checks + + +@pytest.mark.parametrize( + "capabilities,method,params,expected", + [ + ( + types.ClientCapabilities( + workspace=types.WorkspaceClientCapabilities(configuration=False) + ), + types.WORKSPACE_CONFIGURATION, + types.WorkspaceConfigurationParams(items=[]), + "does not support 'workspace/configuration'", + ), + ], +) +def test_params_check_warning( + capabilities: types.ClientCapabilities, method: str, params: Any, expected: str +): + """Ensure that parameter checks work as expected. + + Parameters + ---------- + capabilities + The client's capabilities + + method + The method name to check + + params + The params to check + + expected + The expected warning message + """ + + with pytest.warns(checks.LspSpecificationWarning, match=expected): + checks.check_params_against_client_capabilities(capabilities, method, params) From 96a4c7ec8ff8ab8ecc325be8d8c469cb14f74fd8 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 23 Oct 2023 20:01:29 +0100 Subject: [PATCH 27/50] docs: Document `workspace/configuration` support --- docs/pytest-lsp/guide/language-client.rst | 23 ++++++++++ .../workspace-configuration/server.py | 27 ++++++++++++ .../workspace-configuration/t_server.py | 44 +++++++++++++++++++ lib/pytest-lsp/tests/test_examples.py | 1 + 4 files changed, 95 insertions(+) create mode 100644 lib/pytest-lsp/tests/examples/workspace-configuration/server.py create mode 100644 lib/pytest-lsp/tests/examples/workspace-configuration/t_server.py diff --git a/docs/pytest-lsp/guide/language-client.rst b/docs/pytest-lsp/guide/language-client.rst index 1c35ee7..775ccbf 100644 --- a/docs/pytest-lsp/guide/language-client.rst +++ b/docs/pytest-lsp/guide/language-client.rst @@ -89,3 +89,26 @@ Similar to ``window/logMessage`` above, the client records any :lsp:`window/show :language: python :start-at: @server.feature :end-at: return items + +``workspace/configuration`` +--------------------------- + +The client can respond to :lsp:`workspace/configuration` requests. + +The client supports settings different configuration values for different ``scope_uris`` as well as getting/setting specific configuration ``sections``. +However, to keep the implementation simple the client **will not** fallback to more general configuration scopes if it cannot find a value in the requested scope. + +See the documentation on :meth:`~pytest_lsp.LanguageClient.set_configuration` and :meth:`~pytest_lsp.LanguageClient.get_configuration` for details + +.. card:: test_server.py + + .. literalinclude:: ../../../lib/pytest-lsp/tests/examples/workspace-configuration/t_server.py + :language: python + :start-at: @pytest.mark.asyncio + +.. card:: server.py + + .. literalinclude:: ../../../lib/pytest-lsp/tests/examples/workspace-configuration/server.py + :language: python + :start-at: @server.command + :end-at: return a + c diff --git a/lib/pytest-lsp/tests/examples/workspace-configuration/server.py b/lib/pytest-lsp/tests/examples/workspace-configuration/server.py new file mode 100644 index 0000000..3d35bde --- /dev/null +++ b/lib/pytest-lsp/tests/examples/workspace-configuration/server.py @@ -0,0 +1,27 @@ +from lsprotocol import types +from pygls.server import LanguageServer + +server = LanguageServer("workspace-configuration", "v1") + + +@server.command("server.configuration") +async def configuration(ls: LanguageServer, *args): + results = await ls.get_configuration_async( + types.WorkspaceConfigurationParams( + items=[ + types.ConfigurationItem(scope_uri="file://workspace/file.txt"), + types.ConfigurationItem(section="not.found"), + types.ConfigurationItem(section="values.c"), + ] + ) + ) + + a = results[0]["values"]["a"] + assert results[1] is None + c = results[2] + + return a + c + + +if __name__ == "__main__": + server.start_io() diff --git a/lib/pytest-lsp/tests/examples/workspace-configuration/t_server.py b/lib/pytest-lsp/tests/examples/workspace-configuration/t_server.py new file mode 100644 index 0000000..df382c6 --- /dev/null +++ b/lib/pytest-lsp/tests/examples/workspace-configuration/t_server.py @@ -0,0 +1,44 @@ +import sys + +import pytest +from lsprotocol import types + +import pytest_lsp +from pytest_lsp import ClientServerConfig +from pytest_lsp import LanguageClient + + +@pytest_lsp.fixture( + config=ClientServerConfig(server_command=[sys.executable, "server.py"]), +) +async def client(lsp_client: LanguageClient): + # Setup + params = types.InitializeParams( + capabilities=types.ClientCapabilities( + workspace=types.WorkspaceClientCapabilities(configuration=False) + ) + ) + await lsp_client.initialize_session(params) + + yield + + # Teardown + await lsp_client.shutdown_session() + + +@pytest.mark.asyncio +async def test_configuration(client: LanguageClient): + global_config = {"values": {"a": 42, "c": 4}} + + workspace_uri = "file://workspace/file.txt" + workspace_config = {"a": 1, "c": 1} + + client.set_configuration(global_config) + client.set_configuration( + workspace_config, section="values", scope_uri=workspace_uri + ) + + result = await client.workspace_execute_command_async( + params=types.ExecuteCommandParams(command="server.configuration") + ) + assert result == 5 diff --git a/lib/pytest-lsp/tests/test_examples.py b/lib/pytest-lsp/tests/test_examples.py index 32f47d8..79a505e 100644 --- a/lib/pytest-lsp/tests/test_examples.py +++ b/lib/pytest-lsp/tests/test_examples.py @@ -32,6 +32,7 @@ def setup_test(pytester: pytest.Pytester, example_name: str): ("window-log-message", dict(passed=1)), ("window-show-document", dict(passed=1)), ("window-show-message", dict(passed=1)), + ("workspace-configuration", dict(passed=1, warnings=1)), ], ) def test_documentation_examples(pytester: pytest.Pytester, name: str, expected: dict): From b975d1a959b7b886683dba44dfb52802c3e97ea5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 18:00:18 +0000 Subject: [PATCH 28/50] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 23.9.1 → 23.10.0](https://github.com/psf/black/compare/23.9.1...23.10.0) - [github.com/pre-commit/mirrors-mypy: v1.6.0 → v1.6.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.6.0...v1.6.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4493b7e..7408624 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 23.9.1 + rev: 23.10.0 hooks: - id: black exclude: 'lib/pytest-lsp/pytest_lsp/gen.py' @@ -36,7 +36,7 @@ repos: exclude: 'lib/pytest-lsp/pytest_lsp/gen.py' - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.6.0' + rev: 'v1.6.1' hooks: - id: mypy name: mypy (pytest-lsp) From fbefe5687520827e1e54b3385cf92281100021c1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:53:53 +0000 Subject: [PATCH 29/50] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 23.10.0 → 23.10.1](https://github.com/psf/black/compare/23.10.0...23.10.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7408624..2256e69 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 23.10.0 + rev: 23.10.1 hooks: - id: black exclude: 'lib/pytest-lsp/pytest_lsp/gen.py' From 9652b9d5506f5adc66f7e2f18f27558c25336f17 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Tue, 31 Oct 2023 23:03:00 +0000 Subject: [PATCH 30/50] lsp-devtools: Expose server capabilities via the client --- lib/lsp-devtools/lsp_devtools/client/lsp.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/lsp-devtools/lsp_devtools/client/lsp.py b/lib/lsp-devtools/lsp_devtools/client/lsp.py index 897505f..8912853 100644 --- a/lib/lsp-devtools/lsp_devtools/client/lsp.py +++ b/lib/lsp-devtools/lsp_devtools/client/lsp.py @@ -1,6 +1,8 @@ import importlib.metadata import json +from typing import Optional +from lsprotocol import types from pygls.lsp.client import BaseLanguageClient from pygls.protocol import LanguageServerProtocol @@ -37,3 +39,22 @@ class LanguageClient(BaseLanguageClient): def __init__(self): super().__init__("lsp-devtools", VERSION, protocol_cls=RecordingLSProtocol) + + self._server_capabilities: Optional[types.ServerCapabilities] = None + + @property + def server_capabilities(self) -> types.ServerCapabilities: + if self._server_capabilities is None: + raise RuntimeError( + "sever_capabilities is None - has the server been initialized?" + ) + + return self._server_capabilities + + async def initialize_async( + self, params: types.InitializeParams + ) -> types.InitializeResult: + result = await super().initialize_async(params) + self._server_capabilities = result.capabilities + + return result From b3f7eded4baf9a4e6b2bb82c922480b34280471c Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Tue, 31 Oct 2023 23:06:33 +0000 Subject: [PATCH 31/50] lsp-devtools: Bump textual version --- lib/lsp-devtools/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lsp-devtools/pyproject.toml b/lib/lsp-devtools/pyproject.toml index d0de8ab..4e88cc5 100644 --- a/lib/lsp-devtools/pyproject.toml +++ b/lib/lsp-devtools/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "platformdirs", "pygls>=1.1.0", "stamina", - "textual>=0.38.0", + "textual>=0.41.0", "typing-extensions; python_version<\"3.8\"", ] From 83db47bba72068c0672fe578dbd6a2ea5b797dbd Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Tue, 31 Oct 2023 23:19:05 +0000 Subject: [PATCH 32/50] lsp-devtools: Implement completion item selection This introduces the `EditorView` widget. It's responsible for managing the `TextEditor` widget and any additional UI elements e.g. completion suggestions. This commit tries to lean on the textual framework more, using `self.run_worker` for communicating with the LSP server in the background and a custom message for triggering the display of completion items --- lib/lsp-devtools/changes/108.enhancement.rst | 1 + .../lsp_devtools/client/__init__.py | 20 ++- .../lsp_devtools/client/editor.py | 161 ------------------ .../lsp_devtools/client/editor/__init__.py | 72 ++++++++ .../lsp_devtools/client/editor/completion.py | 57 +++++++ .../lsp_devtools/client/editor/text_editor.py | 143 ++++++++++++++++ 6 files changed, 286 insertions(+), 168 deletions(-) create mode 100644 lib/lsp-devtools/changes/108.enhancement.rst delete mode 100644 lib/lsp-devtools/lsp_devtools/client/editor.py create mode 100644 lib/lsp-devtools/lsp_devtools/client/editor/__init__.py create mode 100644 lib/lsp-devtools/lsp_devtools/client/editor/completion.py create mode 100644 lib/lsp-devtools/lsp_devtools/client/editor/text_editor.py diff --git a/lib/lsp-devtools/changes/108.enhancement.rst b/lib/lsp-devtools/changes/108.enhancement.rst new file mode 100644 index 0000000..4cedcff --- /dev/null +++ b/lib/lsp-devtools/changes/108.enhancement.rst @@ -0,0 +1 @@ +It is now possible to select completion items in the ``lsp-devtools client`` diff --git a/lib/lsp-devtools/lsp_devtools/client/__init__.py b/lib/lsp-devtools/lsp_devtools/client/__init__.py index 23f6024..2d2bcf7 100644 --- a/lib/lsp-devtools/lsp_devtools/client/__init__.py +++ b/lib/lsp-devtools/lsp_devtools/client/__init__.py @@ -25,7 +25,7 @@ from lsp_devtools.inspector import MessagesTable from lsp_devtools.inspector import MessageViewer -from .editor import TextEditor +from .editor import EditorView from .lsp import LanguageClient @@ -35,7 +35,7 @@ def open_file(self, event: DirectoryTree.FileSelected): if not self.parent: return - editor = self.parent.query_one(TextEditor) + editor = self.parent.query_one(EditorView) editor.open_file(event.path) editor.focus() @@ -51,7 +51,6 @@ class LSPClient(App): BINDINGS = [ ("f2", "toggle_explorer", "Explorer"), ("f12", "toggle_devtools", "Devtools"), - # ("ctrl+g", "refresh_table", "Refresh table"), ] def __init__( @@ -74,7 +73,7 @@ def compose(self) -> ComposeResult: yield Header() yield Explorer(".") - yield TextEditor(self.lsp_client) + yield EditorView(self.lsp_client) devtools = Devtools(ScrollableContainer(messages_table), message_viewer) devtools.add_class("-hidden") yield devtools @@ -105,9 +104,12 @@ def action_toggle_explorer(self) -> None: self.screen.set_focus(explorer) async def on_ready(self, event: events.Ready): - editor = self.query_one(TextEditor) - # Start the lsp server. + self.run_worker(self.start_lsp_server()) + + async def start_lsp_server(self): + """Initialize the lsp server session.""" + await self.lsp_client.start_io(self.server_command[0], *self.server_command[1:]) result = await self.lsp_client.initialize_async( types.InitializeParams( @@ -117,7 +119,11 @@ async def on_ready(self, event: events.Ready): ) ) - editor.capabilities = result.capabilities + if info := result.server_info: + name = info.name + version = info.version or "" + self.log(f"Connected to server: {name} {version}") + self.lsp_client.initialized(types.InitializedParams()) @on(Database.Update) diff --git a/lib/lsp-devtools/lsp_devtools/client/editor.py b/lib/lsp-devtools/lsp_devtools/client/editor.py deleted file mode 100644 index fff312d..0000000 --- a/lib/lsp-devtools/lsp_devtools/client/editor.py +++ /dev/null @@ -1,161 +0,0 @@ -import asyncio -import pathlib -from typing import Optional -from typing import Set - -from lsprotocol import types -from pygls import uris as uri -from pygls.capabilities import get_capability -from textual import events -from textual import log -from textual import on -from textual.binding import Binding -from textual.widgets import OptionList -from textual.widgets import TextArea - -from .lsp import LanguageClient - - -class CompletionList(OptionList): - BINDINGS = [ - Binding("escape", "dismiss", "Dismiss", show=False), - Binding("ctrl+j", "dismiss", "Dismiss", show=False), - ] - - @classmethod - def fromresult(cls, result): - """Build a list of completion candidates based on a response from the - language server.""" - candidates = cls() - - if result is None: - return candidates - - if isinstance(result, types.CompletionList): - items = result.items - else: - items = result - - if len(items) == 0: - return candidates - - candidates.add_options(sorted([i.label for i in items])) - return candidates - - def on_blur(self, event: events.Blur): - self.action_dismiss() - - def action_dismiss(self): - self.remove() - if self.parent: - self.app.set_focus(self.parent) # type: ignore - - -class TextEditor(TextArea): - def __init__(self, lsp_client: LanguageClient, *args, **kwargs): - super().__init__(*args, **kwargs) - self.uri = None - self.version = 0 - - self.lsp_client = lsp_client - self.capabilities: Optional[types.ServerCapabilities] = None - - self._tasks: Set[asyncio.Task] = set() - - @property - def completion_triggers(self): - return get_capability( - self.capabilities, # type: ignore - "completion_provider.trigger_characters", - set(), - ) - - def open_file(self, path: pathlib.Path): - self.uri = uri.from_fs_path(str(path.resolve())) - if self.uri is None: - return - - content = path.read_text() - self.version = 0 - self.load_text(content) - - self.lsp_client.text_document_did_open( - types.DidOpenTextDocumentParams( - text_document=types.TextDocumentItem( - uri=self.uri, - language_id="restructuredtext", - version=self.version, - text=content, - ) - ) - ) - - def edit(self, edit): - super().edit(edit) - - if self.uri is None: - return - - self.version += 1 - start_line, start_col = edit.from_location - end_line, end_col = edit.to_location - - self.lsp_client.text_document_did_change( - types.DidChangeTextDocumentParams( - text_document=types.VersionedTextDocumentIdentifier( - version=self.version, uri=self.uri - ), - content_changes=[ - types.TextDocumentContentChangeEvent_Type1( - text=edit.text, - range=types.Range( - start=types.Position(line=start_line, character=start_col), - end=types.Position(line=end_line, character=end_col), - ), - ) - ], - ) - ) - - if len(edit.text) == 0: - return - - char = edit.text[-1] - if char in self.completion_triggers: - self.trigger_completion(end_line, end_col) - - def trigger_completion(self, line: int, character: int): - """Trigger completion at the given location.""" - - if self.uri is None: - return - - task = asyncio.create_task( - self.lsp_client.text_document_completion_async( - types.CompletionParams( - text_document=types.TextDocumentIdentifier(uri=self.uri), - position=types.Position(line=line, character=character), - ) - ) - ) - - self._tasks.add(task) - task.add_done_callback(self.show_completions) - - def show_completions(self, task: asyncio.Task): - self._tasks.discard(task) - - candidates = CompletionList.fromresult(task.result()) - if candidates.option_count == 0: - return - - row, col = self.cursor_location - candidates.offset = (col + 2, row + 1) - - self.mount(candidates) - self.app.set_focus(candidates) - - @on(OptionList.OptionSelected) - def completion_selected(self, event: OptionList.OptionSelected): - log(f"{event.option} was selected!") - event.option_list.action_dismiss() # type: ignore diff --git a/lib/lsp-devtools/lsp_devtools/client/editor/__init__.py b/lib/lsp-devtools/lsp_devtools/client/editor/__init__.py new file mode 100644 index 0000000..48fa1db --- /dev/null +++ b/lib/lsp-devtools/lsp_devtools/client/editor/__init__.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +import pathlib +import typing + +from lsprotocol import types +from textual import on +from textual.app import ComposeResult +from textual.containers import Vertical +from textual.widgets import OptionList + +from .completion import CompletionList +from .text_editor import TextEditor + +if typing.TYPE_CHECKING: + from lsp_devtools.client.lsp import LanguageClient + + +class EditorView(Vertical): + """A container to manage all the widgets that make up a single text editor.""" + + def __init__(self, lsp_client: LanguageClient, *args, **kwargs): + super().__init__(*args, **kwargs) + self.lsp_client = lsp_client + + def compose(self) -> ComposeResult: + yield TextEditor(self.lsp_client) + + def open_file(self, path: pathlib.Path): + editor = self.query_one(TextEditor) + editor.open_file(path) + editor.focus() + + def on_text_editor_completion(self, completion: TextEditor.Completion): + """Render textDocument/completion results.""" + candidates = CompletionList.fromresult(completion.result) + if candidates is None: + return + + editor = self.query_one(TextEditor) + row, col = editor.cursor_location + + gutter_width = 2 # TODO: How to get actual gutter width? + first_line = 0 # TODO: How to get the first visible line number? + candidates.offset = (col + gutter_width, row - first_line + 1) + + self.mount(candidates) + self.app.set_focus(candidates) + + @on(OptionList.OptionSelected) + def insert_selected_completion(self, event: CompletionList.OptionSelected): + """Insert the completion item selected by the user into the editor.""" + selected: types.CompletionItem = event.option.prompt # type: ignore + event.option_list.action_dismiss() # type: ignore + + editor = self.query_one(TextEditor) + if (edit := selected.text_edit) is not None: + # TODO: Support InsertReplaceEdit + if isinstance(edit, types.InsertReplaceEdit): + return + + # TextEdit support. + start = edit.range.start.line, edit.range.start.character + end = edit.range.end.line, edit.range.end.character + + with editor.set_state(suppress_completion=True): + editor.replace( + edit.new_text, start, end, maintain_selection_offset=False + ) + + # TODO: Support insert_text + # TODO: Fallback to label diff --git a/lib/lsp-devtools/lsp_devtools/client/editor/completion.py b/lib/lsp-devtools/lsp_devtools/client/editor/completion.py new file mode 100644 index 0000000..53631d9 --- /dev/null +++ b/lib/lsp-devtools/lsp_devtools/client/editor/completion.py @@ -0,0 +1,57 @@ +from lsprotocol import types +from textual import events +from textual.binding import Binding +from textual.widgets import OptionList + + +class CompletionList(OptionList): + BINDINGS = [ + Binding("escape", "dismiss", "Dismiss", show=False), + ] + + @classmethod + def fromresult(cls, result): + """Build a list of completion candidates based on a response from the + language server.""" + + if result is None: + return None + + if isinstance(result, types.CompletionList): + items = result.items + else: + items = result + + if len(items) == 0: + return None + + candidates = cls() + candidates.add_options( + sorted( + [CompletionItem(i) for i in items], + key=lambda i: i.item.label, # type: ignore + ) + ) + return candidates + + def on_blur(self, event: events.Blur): + self.action_dismiss() + + def action_dismiss(self): + self.remove() + if self.parent: + self.app.set_focus(self.parent) # type: ignore + + +class CompletionItem: + """Renders a completion item for display in a completion list.""" + + def __init__(self, item: types.CompletionItem): + self.item = item + + def __rich__(self): + # TODO: Make pretty + return self.item.label + + def __getattr__(self, key): + return getattr(self.item, key) diff --git a/lib/lsp-devtools/lsp_devtools/client/editor/text_editor.py b/lib/lsp-devtools/lsp_devtools/client/editor/text_editor.py new file mode 100644 index 0000000..74b256c --- /dev/null +++ b/lib/lsp-devtools/lsp_devtools/client/editor/text_editor.py @@ -0,0 +1,143 @@ +from __future__ import annotations + +import contextlib +import pathlib +import typing +from typing import List +from typing import Union + +from lsprotocol import types +from pygls import uris as uri +from pygls.capabilities import get_capability +from textual.message import Message +from textual.widgets import TextArea + +if typing.TYPE_CHECKING: + from lsp_devtools.client.lsp import LanguageClient + +CompletionResult = Union[List[types.CompletionItem], types.CompletionList, None] + + +# TODO: Refactor to +# - emit relevent events. +# - split handlers out into multiple features that can listen and respond +# to these events.. +class TextEditor(TextArea): + """A wrapper around textual's ``TextArea`` widget.""" + + class Completion(Message): + """Emitted when completion results are received.""" + + def __init__(self, result: CompletionResult): + self.result = result + super().__init__() + + def __init__(self, lsp_client: LanguageClient, *args, **kwargs): + super().__init__(*args, **kwargs) + self.uri = None + self.version = 0 + + self.lsp_client = lsp_client + self.suppress_completion = False + + @contextlib.contextmanager + def set_state(self, **kwargs): + """Temporarily override a value on the editor.""" + old_values = {} + for key, value in kwargs.items(): + old_values[key] = getattr(self, key) + setattr(self, key, value) + + yield + + for key, value in old_values.items(): + setattr(self, key, value) + + @property + def completion_triggers(self): + """Return the completion trigger characters registered by the server.""" + return get_capability( + self.lsp_client.server_capabilities, # type: ignore + "completion_provider.trigger_characters", + set(), + ) + + def open_file(self, path: pathlib.Path): + self.uri = uri.from_fs_path(str(path.resolve())) + if self.uri is None: + return + + content = path.read_text() + self.version = 0 + self.load_text(content) + + self.lsp_client.text_document_did_open( + types.DidOpenTextDocumentParams( + text_document=types.TextDocumentItem( + uri=self.uri, + language_id="restructuredtext", + version=self.version, + text=content, + ) + ) + ) + + def edit(self, edit): + """Extend the base ``edit()`` method to. + + - Ensure that any edits that are made to the document are syncronised with the + server. + - Completions are triggered if necessary. + """ + super().edit(edit) + + if self.uri is None: + return + + self.version += 1 + start_line, start_col = edit.from_location + end_line, end_col = edit.to_location + + self.lsp_client.text_document_did_change( + types.DidChangeTextDocumentParams( + text_document=types.VersionedTextDocumentIdentifier( + version=self.version, uri=self.uri + ), + content_changes=[ + types.TextDocumentContentChangeEvent_Type1( + text=edit.text, + range=types.Range( + start=types.Position(line=start_line, character=start_col), + end=types.Position(line=end_line, character=end_col), + ), + ) + ], + ) + ) + + if len(edit.text) == 0: + return + + char = edit.text[-1] + if not self.suppress_completion and char in self.completion_triggers: + # TODO: How to send $/cancelRequest if a worker is cancelled? + self.run_worker( + self.trigger_completion(end_line, end_col), + group="lsp-completion", + exclusive=True, + ) + + async def trigger_completion(self, line: int, character: int): + """Trigger completion at the given location.""" + + if self.uri is None: + return + + result = await self.lsp_client.text_document_completion_async( + types.CompletionParams( + text_document=types.TextDocumentIdentifier(uri=self.uri), + position=types.Position(line=line, character=character), + ) + ) + + self.post_message(self.Completion(result)) From a51c9cbe5a688c387ebb46c6637ab2a40da36a57 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 11 Nov 2023 20:15:34 +0000 Subject: [PATCH 33/50] lsp-devtools: Fix `lsp-devtools inspect` command --- lib/lsp-devtools/lsp_devtools/inspector/__init__.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/lsp-devtools/lsp_devtools/inspector/__init__.py b/lib/lsp-devtools/lsp_devtools/inspector/__init__.py index a531c00..c8ae11e 100644 --- a/lib/lsp-devtools/lsp_devtools/inspector/__init__.py +++ b/lib/lsp-devtools/lsp_devtools/inspector/__init__.py @@ -157,9 +157,8 @@ class LSPInspector(App): def __init__(self, db: Database, server: AgentServer, *args, **kwargs): super().__init__(*args, **kwargs) - db.app = self self.db = db - """Where the data for the app is being held""" + db.app = self self.server = server """Server used to manage connections to lsp servers.""" @@ -193,9 +192,11 @@ async def on_ready(self, event: Ready): self._async_tasks.append( asyncio.create_task(self.server.start_tcp("localhost", 8765)) ) - await self.update_table() + table = self.query_one(MessagesTable) + await table.update() - async def update_table(self): + @on(Database.Update) + async def update_table(self, event: Database.Update): table = self.query_one(MessagesTable) await table.update() @@ -255,7 +256,7 @@ def setup_server(db: Database): return server -def tui(args, extra: List[str]): +def inspector(args, extra: List[str]): db = Database(args.dbpath) server = setup_server(db) @@ -298,4 +299,4 @@ def cli(commands: argparse._SubParsersAction): connect.add_argument( "-p", "--port", type=int, default=8765, help="the port to connect to." ) - cmd.set_defaults(run=tui) + cmd.set_defaults(run=inspector) From f3fa13ed289de8bca946e6900682b574770cb3c1 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 14:47:08 +0000 Subject: [PATCH 34/50] pytest-lsp: Add option to integrate with `lsp-devtools` --- lib/pytest-lsp/changes/97.feature.rst | 1 + lib/pytest-lsp/pytest_lsp/__init__.py | 2 + lib/pytest-lsp/pytest_lsp/plugin.py | 61 +++++++++++++++++++++++++-- lib/pytest-lsp/tests/test_plugin.py | 61 +++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 lib/pytest-lsp/changes/97.feature.rst diff --git a/lib/pytest-lsp/changes/97.feature.rst b/lib/pytest-lsp/changes/97.feature.rst new file mode 100644 index 0000000..15847e5 --- /dev/null +++ b/lib/pytest-lsp/changes/97.feature.rst @@ -0,0 +1 @@ +``pytest-lsp`` is now able to integrate with ``lsp-devtools``, run ``pytest`` with the ``--lsp-devtools`` flag to enable the integration. diff --git a/lib/pytest-lsp/pytest_lsp/__init__.py b/lib/pytest-lsp/pytest_lsp/__init__.py index c205546..dce742f 100644 --- a/lib/pytest-lsp/pytest_lsp/__init__.py +++ b/lib/pytest-lsp/pytest_lsp/__init__.py @@ -5,6 +5,7 @@ from .client import make_test_lsp_client from .plugin import ClientServerConfig from .plugin import fixture +from .plugin import pytest_addoption from .plugin import pytest_runtest_makereport from .protocol import LanguageClientProtocol @@ -17,5 +18,6 @@ "client_capabilities", "fixture", "make_test_lsp_client", + "pytest_addoption", "pytest_runtest_makereport", ] diff --git a/lib/pytest-lsp/pytest_lsp/plugin.py b/lib/pytest-lsp/pytest_lsp/plugin.py index af7e94c..2fcdc51 100644 --- a/lib/pytest-lsp/pytest_lsp/plugin.py +++ b/lib/pytest-lsp/pytest_lsp/plugin.py @@ -35,14 +35,66 @@ class ClientServerConfig: server_env: Optional[Dict[str, str]] = attrs.field(default=None) """Environment variables to set when starting the server.""" - async def start(self) -> JsonRPCClient: - """Return the client instance to use for the test.""" + def _get_devtools_command(self, server: str) -> List[str]: + """Get the lsp-devtools command required to connect to the given ``server``""" + + if ":" in server: + host, port = server.split(":") + else: + host, port = "localhost", server + + try: + int(port) + except ValueError as e: + raise ValueError(f"Invalid port number: {port!r}") from e + + return ["lsp-devtools", "agent", "--host", host, "--port", port, "--"] + + def get_server_command(self, devtools: Optional[str] = None) -> List[str]: + """Get the command to start the server with.""" + server_command = [] + if devtools is not None: + server_command.extend(self._get_devtools_command(devtools)) + + server_command.extend(self.server_command) + + return server_command + + async def start(self, devtools: Optional[str] = None) -> JsonRPCClient: + """Return the client instance to use for the test. + + Parameters + ---------- + devtools + If set, enable ``lsp-devtools`` integration, should be of the form + ```` or ``:``. Where ```` and ```` + describe how to connect to an ``lsp-devtools`` server program. + + Returns + ------- + JsonRPCClient + The client instance to use in the test. + """ client = self.client_factory() + server_command = self.get_server_command(devtools) - await client.start_io(*self.server_command, env=self.server_env) + await client.start_io(*server_command, env=self.server_env) return client +def pytest_addoption(parser): + group = parser.getgroup("lsp") + group.addoption( + "--lsp-devtools", + dest="devtools", + nargs="?", + action="store", + default=None, + const="localhost:8765", + help="Enable lsp-devtools integration.", + ) + + def pytest_runtest_makereport(item: pytest.Item, call: pytest.CallInfo): """Add any captured log messages to the report.""" client: Optional[LanguageClient] = None @@ -144,7 +196,8 @@ def fixture( def wrapper(fn): @pytest_asyncio.fixture(**kwargs) async def the_fixture(request): - client = await config.start() + devtools = request.config.getoption("devtools") + client = await config.start(devtools=devtools) kwargs = get_fixture_arguments(fn, client, request) result = fn(**kwargs) diff --git a/lib/pytest-lsp/tests/test_plugin.py b/lib/pytest-lsp/tests/test_plugin.py index 15f5b13..1cb06d5 100644 --- a/lib/pytest-lsp/tests/test_plugin.py +++ b/lib/pytest-lsp/tests/test_plugin.py @@ -1,9 +1,70 @@ import pathlib import sys +from typing import Any +from typing import Dict +from typing import List import pygls.uris as uri import pytest +from pytest_lsp.plugin import ClientServerConfig + + +@pytest.mark.parametrize( + "config, kwargs, expected", + [ + (ClientServerConfig(server_command=["command"]), {}, ["command"]), + ( + ClientServerConfig(server_command=["command"]), + {"devtools": "1234"}, + [ + "lsp-devtools", + "agent", + "--host", + "localhost", + "--port", + "1234", + "--", + "command", + ], + ), + ( + ClientServerConfig(server_command=["command"]), + {"devtools": "localhost:1234"}, + [ + "lsp-devtools", + "agent", + "--host", + "localhost", + "--port", + "1234", + "--", + "command", + ], + ), + ( + ClientServerConfig(server_command=["command"]), + {"devtools": "127.0.0.1:1234"}, + [ + "lsp-devtools", + "agent", + "--host", + "127.0.0.1", + "--port", + "1234", + "--", + "command", + ], + ), + ], +) +def test_get_server_command( + config: ClientServerConfig, kwargs: Dict[str, Any], expected: List[str] +): + """Ensure that we can build the server start command correctly.""" + actual = config.get_server_command(**kwargs) + assert expected == actual + def setup_test(pytester: pytest.Pytester, server_name: str, test_code: str): """Boilerplate for setting up a test.""" From bed8f55d3790018eb1ce475af911076f7174b1d2 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 14:59:49 +0000 Subject: [PATCH 35/50] docs: Rename `lsp-devtools tui` to `lsp-devtools inspect` --- docs/lsp-devtools/guide.rst | 2 +- docs/lsp-devtools/guide/getting-started.rst | 4 ++-- docs/lsp-devtools/guide/inspect-command.rst | 10 ++++++++++ docs/lsp-devtools/guide/tui-command.rst | 2 -- 4 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 docs/lsp-devtools/guide/inspect-command.rst delete mode 100644 docs/lsp-devtools/guide/tui-command.rst diff --git a/docs/lsp-devtools/guide.rst b/docs/lsp-devtools/guide.rst index 01be0ae..1332af7 100644 --- a/docs/lsp-devtools/guide.rst +++ b/docs/lsp-devtools/guide.rst @@ -6,4 +6,4 @@ User Guide guide/getting-started guide/record-command - guide/tui-command + guide/inspect-command diff --git a/docs/lsp-devtools/guide/getting-started.rst b/docs/lsp-devtools/guide/getting-started.rst index 6e8aace..5e7771d 100644 --- a/docs/lsp-devtools/guide/getting-started.rst +++ b/docs/lsp-devtools/guide/getting-started.rst @@ -97,9 +97,9 @@ Currently ``lsp-devtools`` provides the following applications See :doc:`/lsp-devtools/guide/record-command` for details -``lsp-devtools tui`` +``lsp-devtools inspect`` An interactive terminal application, powered by `textual `_. .. figure:: /images/tui-screenshot.svg - See :doc:`/lsp-devtools/guide/tui-command` for details + See :doc:`/lsp-devtools/guide/inspect-command` for details diff --git a/docs/lsp-devtools/guide/inspect-command.rst b/docs/lsp-devtools/guide/inspect-command.rst new file mode 100644 index 0000000..69e05df --- /dev/null +++ b/docs/lsp-devtools/guide/inspect-command.rst @@ -0,0 +1,10 @@ +LSP Inspector +============= + +.. figure:: /images/tui-screenshot.svg + :align: center + + The ``lsp-devtools inspect`` command + + +The ``lsp-devtools inspect`` command opens an application that allows you to browse all the messages sent between a client and server during an LSP session. diff --git a/docs/lsp-devtools/guide/tui-command.rst b/docs/lsp-devtools/guide/tui-command.rst deleted file mode 100644 index b482117..0000000 --- a/docs/lsp-devtools/guide/tui-command.rst +++ /dev/null @@ -1,2 +0,0 @@ -TUI Application -=============== From a36c701b3789abd40dab0302444c183fdde1ef1d Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 15:01:33 +0000 Subject: [PATCH 36/50] docs: Add "How To" section to pytest-lsp docs - Add new guide on integrating with pytest-lsp - Move guide on testing generic JSON-RPC servers to how to section --- docs/index.rst | 1 + docs/pytest-lsp/guide.rst | 1 - docs/pytest-lsp/howto.rst | 8 +++++++ .../howto/integrate-with-lsp-devtools.rst | 22 +++++++++++++++++++ .../testing-json-rpc-servers.rst | 4 ++-- 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 docs/pytest-lsp/howto.rst create mode 100644 docs/pytest-lsp/howto/integrate-with-lsp-devtools.rst rename docs/pytest-lsp/{guide => howto}/testing-json-rpc-servers.rst (97%) diff --git a/docs/index.rst b/docs/index.rst index 200b07e..66c0492 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -78,6 +78,7 @@ pytest-lsp :caption: pytest-lsp pytest-lsp/guide + pytest-lsp/howto pytest-lsp/reference pytest-lsp/changelog diff --git a/docs/pytest-lsp/guide.rst b/docs/pytest-lsp/guide.rst index b8b4f4d..6bdfb6a 100644 --- a/docs/pytest-lsp/guide.rst +++ b/docs/pytest-lsp/guide.rst @@ -9,4 +9,3 @@ User Guide guide/client-capabilities guide/fixtures guide/troubleshooting - guide/testing-json-rpc-servers diff --git a/docs/pytest-lsp/howto.rst b/docs/pytest-lsp/howto.rst new file mode 100644 index 0000000..0e1f4fe --- /dev/null +++ b/docs/pytest-lsp/howto.rst @@ -0,0 +1,8 @@ +How To +====== + +.. toctree:: + :maxdepth: 2 + + Integrate with lsp-devtools + Test Generic JSON-RPC Servers diff --git a/docs/pytest-lsp/howto/integrate-with-lsp-devtools.rst b/docs/pytest-lsp/howto/integrate-with-lsp-devtools.rst new file mode 100644 index 0000000..27464ba --- /dev/null +++ b/docs/pytest-lsp/howto/integrate-with-lsp-devtools.rst @@ -0,0 +1,22 @@ +How To Integrate ``pytest-lsp`` with ``lsp-devtools`` +===================================================== + +``pytest-lsp`` is able to forward LSP traffic to utilities like :doc:`lsp-devtools record ` and :doc:`lsp-devtools inspect ` + +.. important:: + + ``pytest-lsp`` does not depend on ``lsp-devtools`` directly and instead assumes that the ``lsp-devtools`` command is available on your ``$PATH``. + It's recommended to install ``lsp-devtools`` via `pipx `__:: + + $ pipx install lsp-devtools + +To enable the integration pass the ``--lsp-devtools`` flag to ``pytest``:: + + $ pytest --lsp-devtools + +This will make ``pytest-lsp`` send the captured traffic to an ``lsp-devtools`` command listening on ``localhost:8765`` by default. + +To change the default host and/or port number you can pass it to the ``--lsp-devtools`` cli option:: + + $ pytest --lsp-devtools 1234 # change port number + $ pytest --lsp-devtools 127.0.01:1234 # change host and port diff --git a/docs/pytest-lsp/guide/testing-json-rpc-servers.rst b/docs/pytest-lsp/howto/testing-json-rpc-servers.rst similarity index 97% rename from docs/pytest-lsp/guide/testing-json-rpc-servers.rst rename to docs/pytest-lsp/howto/testing-json-rpc-servers.rst index 1005c59..f6e238e 100644 --- a/docs/pytest-lsp/guide/testing-json-rpc-servers.rst +++ b/docs/pytest-lsp/howto/testing-json-rpc-servers.rst @@ -1,5 +1,5 @@ -Testing JSON-RPC Servers -======================== +How To Test Generic JSON-RPC Servers +==================================== While ``pytest-lsp`` is primarily focused on writing tests for LSP servers it is possible to reuse some of the machinery to test other JSON-RPC servers. From 57a0ef5fd8f25f5c8683fd398ddbdf9029aa5abc Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 15:02:36 +0000 Subject: [PATCH 37/50] docs: Rename capabilities to client capabilities --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 66c0492..2e7c601 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,7 +20,7 @@ Client Capability Index .. toctree:: :maxdepth: 2 :hidden: - :caption: Capabilities + :caption: Client Capabilities capabilities/text-document capabilities/workspace From 3ba4d3606b57717f24142531d310fc85694172d5 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 15:30:19 +0000 Subject: [PATCH 38/50] lsp-devtools: Don't close server on client exit This allows commands like ``lsp-devtools record`` or ``lsp-devtools inspect`` to capture multiple sessions without exiting --- lib/lsp-devtools/changes/110.enhancement.rst | 1 + lib/lsp-devtools/lsp_devtools/agent/server.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 lib/lsp-devtools/changes/110.enhancement.rst diff --git a/lib/lsp-devtools/changes/110.enhancement.rst b/lib/lsp-devtools/changes/110.enhancement.rst new file mode 100644 index 0000000..6fb105d --- /dev/null +++ b/lib/lsp-devtools/changes/110.enhancement.rst @@ -0,0 +1 @@ +Commands like ``lsp-devtools record`` and ``lsp-devtools inspect`` will no longer exit/stop capturing messages after the first LSP session exits diff --git a/lib/lsp-devtools/lsp_devtools/agent/server.py b/lib/lsp-devtools/lsp_devtools/agent/server.py index f9633a2..0b8077b 100644 --- a/lib/lsp-devtools/lsp_devtools/agent/server.py +++ b/lib/lsp-devtools/lsp_devtools/agent/server.py @@ -47,8 +47,11 @@ async def handle_client(reader, writer): writer.close() await writer.wait_closed() - if self._tcp_server is not None: - self._tcp_server.cancel() + # Uncomment if we ever need to introduce a mode where the server stops + # automatically once a session ends. + # + # if self._tcp_server is not None: + # self._tcp_server.cancel() server = await asyncio.start_server(handle_client, host, port) async with server: From 6f63b78f3aad7741e65fe68380e7aa9a2b84ccf2 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 19:06:00 +0000 Subject: [PATCH 39/50] pytest-lsp: Add test cases covering existing checks --- lib/pytest-lsp/pytest_lsp/checks.py | 2 +- lib/pytest-lsp/tests/test_checks.py | 88 +++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/lib/pytest-lsp/pytest_lsp/checks.py b/lib/pytest-lsp/pytest_lsp/checks.py index 08d996a..e004b50 100644 --- a/lib/pytest-lsp/pytest_lsp/checks.py +++ b/lib/pytest-lsp/pytest_lsp/checks.py @@ -143,7 +143,7 @@ def check_completion_item( if isinstance(item.documentation, types.MarkupContent): kind = item.documentation.kind - message = f"Client does not support documentation format '{kind}'" + message = f"Client does not support documentation format {kind.value!r}" assert kind in documentation_formats, message if item.insert_text_format == types.InsertTextFormat.Snippet: diff --git a/lib/pytest-lsp/tests/test_checks.py b/lib/pytest-lsp/tests/test_checks.py index 3d5608a..3a6c676 100644 --- a/lib/pytest-lsp/tests/test_checks.py +++ b/lib/pytest-lsp/tests/test_checks.py @@ -5,6 +5,11 @@ from pytest_lsp import checks +a_range = types.Range( + start=types.Position(line=1, character=0), + end=types.Position(line=2, character=0), +) + @pytest.mark.parametrize( "capabilities,method,params,expected", @@ -41,3 +46,86 @@ def test_params_check_warning( with pytest.warns(checks.LspSpecificationWarning, match=expected): checks.check_params_against_client_capabilities(capabilities, method, params) + + +@pytest.mark.parametrize( + "capabilities,method,result,expected", + [ + ( + types.ClientCapabilities( + text_document=types.TextDocumentClientCapabilities( + completion=types.CompletionClientCapabilities() + ) + ), + types.TEXT_DOCUMENT_COMPLETION, + [types.CompletionItem(label="item", commit_characters=["."])], + "does not support commit characters", + ), + ( + types.ClientCapabilities( + text_document=types.TextDocumentClientCapabilities( + completion=types.CompletionClientCapabilities() + ) + ), + types.TEXT_DOCUMENT_COMPLETION, + [ + types.CompletionItem( + label="item", + documentation=types.MarkupContent( + value="", kind=types.MarkupKind.Markdown + ), + ) + ], + "does not support documentation format 'markdown'", + ), + ( + types.ClientCapabilities( + text_document=types.TextDocumentClientCapabilities( + completion=types.CompletionClientCapabilities() + ) + ), + types.TEXT_DOCUMENT_COMPLETION, + [ + types.CompletionItem( + label="item", + insert_text_format=types.InsertTextFormat.Snippet, + ) + ], + "does not support snippets", + ), + ( + types.ClientCapabilities( + text_document=types.TextDocumentClientCapabilities( + document_link=types.DocumentLinkClientCapabilities( + tooltip_support=False + ) + ) + ), + types.TEXT_DOCUMENT_DOCUMENT_LINK, + [types.DocumentLink(range=a_range, tooltip="a tooltip")], + "does not support tooltips", + ), + ], +) +def test_result_check_warning( + capabilities: types.ClientCapabilities, method: str, result: Any, expected: str +): + """Ensure that parameter checks work as expected. + + Parameters + ---------- + capabilities + The client's capabilities + + method + The method name to check + + params + The params to check + + expected + The expected warning message + """ + + with pytest.warns(checks.LspSpecificationWarning, match=expected): + checks.check_result_against_client_capabilities(capabilities, method, result) From e157ca3471658597124e546f63a81e86b69fc8a6 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 19:06:56 +0000 Subject: [PATCH 40/50] pytest-lsp: Add checks for `window/workDoneProgress/create` --- lib/pytest-lsp/pytest_lsp/checks.py | 11 +++++++++++ lib/pytest-lsp/tests/test_checks.py | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/pytest-lsp/pytest_lsp/checks.py b/lib/pytest-lsp/pytest_lsp/checks.py index e004b50..1dd9e3e 100644 --- a/lib/pytest-lsp/pytest_lsp/checks.py +++ b/lib/pytest-lsp/pytest_lsp/checks.py @@ -245,6 +245,17 @@ def document_links( assert tooltip_support, "Client does not support tooltips." +@check_params_of(method=types.WINDOW_WORK_DONE_PROGRESS_CREATE) +def work_done_progress_create( + capabilities: types.ClientCapabilities, + params: types.WorkDoneProgressCreateParams, +): + """Assert that the client has support for ``window/workDoneProgress/create`` + requests.""" + is_supported = get_capability(capabilities, "window.workDoneProgress", False) + assert is_supported, "Client does not support 'window/workDoneProgress/create'" + + @check_params_of(method=types.WORKSPACE_CONFIGURATION) def workspace_configuration( capabilities: types.ClientCapabilities, diff --git a/lib/pytest-lsp/tests/test_checks.py b/lib/pytest-lsp/tests/test_checks.py index 3a6c676..8cf6ccf 100644 --- a/lib/pytest-lsp/tests/test_checks.py +++ b/lib/pytest-lsp/tests/test_checks.py @@ -14,6 +14,14 @@ @pytest.mark.parametrize( "capabilities,method,params,expected", [ + ( + types.ClientCapabilities( + window=types.WindowClientCapabilities(work_done_progress=False) + ), + types.WINDOW_WORK_DONE_PROGRESS_CREATE, + types.WorkDoneProgressCreateParams(token="id-123"), + "does not support 'window/workDoneProgress/create'", + ), ( types.ClientCapabilities( workspace=types.WorkspaceClientCapabilities(configuration=False) From c0a3f11d3f73283f819e5dbdac5cbdd664530a1f Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 20:43:30 +0000 Subject: [PATCH 41/50] pytest-lsp: Add support for `window/workDoneProgress/create` --- docs/pytest-lsp/guide/language-client.rst | 21 ++++++ lib/pytest-lsp/changes/91.feature.rst | 1 + lib/pytest-lsp/pytest_lsp/client.py | 49 +++++++++++++- lib/pytest-lsp/pytest_lsp/protocol.py | 7 +- .../examples/window-create-progress/server.py | 64 +++++++++++++++++++ .../window-create-progress/t_server.py | 61 ++++++++++++++++++ lib/pytest-lsp/tests/test_examples.py | 29 ++++++--- 7 files changed, 219 insertions(+), 13 deletions(-) create mode 100644 lib/pytest-lsp/changes/91.feature.rst create mode 100644 lib/pytest-lsp/tests/examples/window-create-progress/server.py create mode 100644 lib/pytest-lsp/tests/examples/window-create-progress/t_server.py diff --git a/docs/pytest-lsp/guide/language-client.rst b/docs/pytest-lsp/guide/language-client.rst index 775ccbf..b6f1fb8 100644 --- a/docs/pytest-lsp/guide/language-client.rst +++ b/docs/pytest-lsp/guide/language-client.rst @@ -90,6 +90,27 @@ Similar to ``window/logMessage`` above, the client records any :lsp:`window/show :start-at: @server.feature :end-at: return items +``window/workDoneProgress/create`` +---------------------------------- + +The client can respond to :lsp:`window/workDoneProgress/create` requests and handle associated :lsp:`$/progress` +notifications + +.. card:: test_server.py + + .. literalinclude:: ../../../lib/pytest-lsp/tests/examples/window-create-progress/t_server.py + :language: python + :start-at: @pytest.mark.asyncio + :end-before: @pytest.mark.asyncio + +.. card:: server.py + + .. literalinclude:: ../../../lib/pytest-lsp/tests/examples/window-create-progress/server.py + :language: python + :start-at: @server.command + :end-at: return + + ``workspace/configuration`` --------------------------- diff --git a/lib/pytest-lsp/changes/91.feature.rst b/lib/pytest-lsp/changes/91.feature.rst new file mode 100644 index 0000000..b0a673d --- /dev/null +++ b/lib/pytest-lsp/changes/91.feature.rst @@ -0,0 +1 @@ +pytest-lsp's ``LanguageClient`` is now able to handle ``window/workDoneProgress/create`` requests. diff --git a/lib/pytest-lsp/pytest_lsp/client.py b/lib/pytest-lsp/pytest_lsp/client.py index 042cd66..4698917 100644 --- a/lib/pytest-lsp/pytest_lsp/client.py +++ b/lib/pytest-lsp/pytest_lsp/client.py @@ -6,10 +6,12 @@ import sys import traceback import typing +import warnings from typing import Any from typing import Dict from typing import List from typing import Optional +from typing import Type from typing import Union from lsprotocol import types @@ -20,6 +22,7 @@ from pygls.lsp.client import BaseLanguageClient from pygls.protocol import default_converter +from .checks import LspSpecificationWarning from .protocol import LanguageClientProtocol if sys.version_info.minor < 9: @@ -47,8 +50,7 @@ def __init__(self, *args, configuration: Optional[Dict[str, Any]] = None, **kwar """The client's capabilities.""" self.shown_documents: List[types.ShowDocumentParams] = [] - """Used to keep track of the documents requested to be shown via a - ``window/showDocument`` request.""" + """Holds any received show document requests.""" self.messages: List[types.ShowMessageParams] = [] """Holds any received ``window/showMessage`` requests.""" @@ -57,7 +59,12 @@ def __init__(self, *args, configuration: Optional[Dict[str, Any]] = None, **kwar """Holds any received ``window/logMessage`` requests.""" self.diagnostics: Dict[str, List[types.Diagnostic]] = {} - """Used to hold any recieved diagnostics.""" + """Holds any recieved diagnostics.""" + + self.progress_reports: Dict[ + types.ProgressToken, List[types.ProgressParams] + ] = {} + """Holds any received progress updates.""" self.error: Optional[Exception] = None """Indicates if the client encountered an error.""" @@ -283,6 +290,42 @@ def publish_diagnostics( ): client.diagnostics[params.uri] = params.diagnostics + @client.feature(types.WINDOW_WORK_DONE_PROGRESS_CREATE) + def create_work_done_progress( + client: LanguageClient, params: types.WorkDoneProgressCreateParams + ): + if params.token in client.progress_reports: + # TODO: Send an error reponse to the client - might require changes + # to pygls... + warnings.warn( + f"Duplicate progress token: {params.token!r}", LspSpecificationWarning + ) + + client.progress_reports.setdefault(params.token, []) + return None + + @client.feature(types.PROGRESS) + def progress(client: LanguageClient, params: types.ProgressParams): + if params.token not in client.progress_reports: + warnings.warn( + f"Unknown progress token: {params.token!r}", LspSpecificationWarning + ) + + if not params.value: + return + + if (kind := params.value.get("kind", None)) == "begin": + type_: Type[Any] = types.WorkDoneProgressBegin + elif kind == "report": + type_ = types.WorkDoneProgressReport + elif kind == "end": + type_ = types.WorkDoneProgressEnd + else: + raise TypeError(f"Unknown progress kind: {kind!r}") + + value = client.protocol._converter.structure(params.value, type_) + client.progress_reports.setdefault(params.token, []).append(value) + @client.feature(types.WINDOW_LOG_MESSAGE) def log_message(client: LanguageClient, params: types.LogMessageParams): client.log_messages.append(params) diff --git a/lib/pytest-lsp/pytest_lsp/protocol.py b/lib/pytest-lsp/pytest_lsp/protocol.py index e849b9f..2068bf5 100644 --- a/lib/pytest-lsp/pytest_lsp/protocol.py +++ b/lib/pytest-lsp/pytest_lsp/protocol.py @@ -57,6 +57,8 @@ def _handle_notification(self, method_name, params): async def send_request_async(self, method, params=None): """Wrap pygls' ``send_request_async`` implementation. This will + - Check the params to see if they're compatible with the client's stated + capabilities - Check the result to see if it's compatible with the client's stated capabilities @@ -71,8 +73,11 @@ async def send_request_async(self, method, params=None): Returns ------- Any - The response's result + The result """ + check_params_against_client_capabilities( + self._server.capabilities, method, params + ) result = await super().send_request_async(method, params) check_result_against_client_capabilities( self._server.capabilities, method, result # type: ignore diff --git a/lib/pytest-lsp/tests/examples/window-create-progress/server.py b/lib/pytest-lsp/tests/examples/window-create-progress/server.py new file mode 100644 index 0000000..b2819fa --- /dev/null +++ b/lib/pytest-lsp/tests/examples/window-create-progress/server.py @@ -0,0 +1,64 @@ +from unittest.mock import Mock + +from lsprotocol import types +from pygls.server import LanguageServer + +server = LanguageServer("window-create-progress", "v1") + + +@server.command("do.progress") +async def do_progress(ls: LanguageServer, *args): + token = "a-token" + + await ls.progress.create_async(token) + + # Begin + ls.progress.begin( + token, + types.WorkDoneProgressBegin(title="Indexing", percentage=0), + ) + # Report + for i in range(1, 4): + ls.progress.report( + token, + types.WorkDoneProgressReport(message=f"{i * 25}%", percentage=i * 25), + ) + # End + ls.progress.end(token, types.WorkDoneProgressEnd(message="Finished")) + + return "a result" + + +@server.command("duplicate.progress") +async def duplicate_progress(ls: LanguageServer, *args): + token = "duplicate-token" + + # Need to stop pygls preventing us from using the progress API wrong. + ls.progress._check_token_registered = Mock() + await ls.progress.create_async(token) + + # pytest-lsp should return an error here. + await ls.progress.create_async(token) + + +@server.command("no.progress") +async def no_progress(ls: LanguageServer, *args): + token = "undefined-token" + + # Begin + ls.progress.begin( + token, + types.WorkDoneProgressBegin(title="Indexing", percentage=0, cancellable=False), + ) + # Report + for i in range(1, 4): + ls.progress.report( + token, + types.WorkDoneProgressReport(message=f"{i * 25}%", percentage=i * 25), + ) + # End + ls.progress.end(token, types.WorkDoneProgressEnd(message="Finished")) + + +if __name__ == "__main__": + server.start_io() diff --git a/lib/pytest-lsp/tests/examples/window-create-progress/t_server.py b/lib/pytest-lsp/tests/examples/window-create-progress/t_server.py new file mode 100644 index 0000000..f80a401 --- /dev/null +++ b/lib/pytest-lsp/tests/examples/window-create-progress/t_server.py @@ -0,0 +1,61 @@ +import sys + +import pytest +from lsprotocol import types + +import pytest_lsp +from pytest_lsp import ClientServerConfig +from pytest_lsp import LanguageClient +from pytest_lsp import LspSpecificationWarning + + +@pytest_lsp.fixture( + config=ClientServerConfig(server_command=[sys.executable, "server.py"]), +) +async def client(lsp_client: LanguageClient): + # Setup + params = types.InitializeParams(capabilities=types.ClientCapabilities()) + await lsp_client.initialize_session(params) + + yield + + # Teardown + await lsp_client.shutdown_session() + + +@pytest.mark.asyncio +async def test_progress(client: LanguageClient): + result = await client.workspace_execute_command_async( + params=types.ExecuteCommandParams(command="do.progress") + ) + + assert result == "a result" + + progress = client.progress_reports["a-token"] + assert progress == [ + types.WorkDoneProgressBegin(title="Indexing", percentage=0), + types.WorkDoneProgressReport(message="25%", percentage=25), + types.WorkDoneProgressReport(message="50%", percentage=50), + types.WorkDoneProgressReport(message="75%", percentage=75), + types.WorkDoneProgressEnd(message="Finished"), + ] + + +@pytest.mark.asyncio +async def test_duplicate_progress(client: LanguageClient): + with pytest.warns( + LspSpecificationWarning, match="Duplicate progress token: 'duplicate-token'" + ): + await client.workspace_execute_command_async( + params=types.ExecuteCommandParams(command="duplicate.progress") + ) + + +@pytest.mark.asyncio +async def test_unknown_progress(client: LanguageClient): + with pytest.warns( + LspSpecificationWarning, match="Unknown progress token: 'undefined-token'" + ): + await client.workspace_execute_command_async( + params=types.ExecuteCommandParams(command="no.progress") + ) diff --git a/lib/pytest-lsp/tests/test_examples.py b/lib/pytest-lsp/tests/test_examples.py index 79a505e..956d4d2 100644 --- a/lib/pytest-lsp/tests/test_examples.py +++ b/lib/pytest-lsp/tests/test_examples.py @@ -25,17 +25,28 @@ def setup_test(pytester: pytest.Pytester, example_name: str): @pytest.mark.parametrize( "name, expected", [ - ("diagnostics", dict(passed=1)), - ("getting-started", dict(passed=1)), - ("fixture-passthrough", dict(passed=1)), - ("parameterised-clients", dict(passed=2)), - ("window-log-message", dict(passed=1)), - ("window-show-document", dict(passed=1)), - ("window-show-message", dict(passed=1)), - ("workspace-configuration", dict(passed=1, warnings=1)), + pytest.param("diagnostics", dict(passed=1), id="diagnostics"), + pytest.param("getting-started", dict(passed=1), id="getting-started"), + pytest.param("fixture-passthrough", dict(passed=1), id="fixture-passthrough"), + pytest.param( + "parameterised-clients", dict(passed=2), id="parameterised-clients" + ), + pytest.param("window-log-message", dict(passed=1), id="window-log-message"), + pytest.param( + "window-create-progress", + dict(passed=3), + id="window-create-progress", + ), + pytest.param("window-show-document", dict(passed=1), id="window-show-document"), + pytest.param("window-show-message", dict(passed=1), id="window-show-message"), + pytest.param( + "workspace-configuration", + dict(passed=1, warnings=1), + id="workspace-configuration", + ), ], ) -def test_documentation_examples(pytester: pytest.Pytester, name: str, expected: dict): +def test_examples(pytester: pytest.Pytester, name: str, expected: dict): """Ensure that the examples included in the documentation work as expected.""" setup_test(pytester, name) From 4bac0a501489c6de5d257be4b490bc160f69df18 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 23:16:57 +0000 Subject: [PATCH 42/50] pytest-lsp: Use hatch for packaging --- lib/pytest-lsp/hatch.toml | 9 +++++++++ lib/pytest-lsp/pyproject.toml | 11 ++++------- 2 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 lib/pytest-lsp/hatch.toml diff --git a/lib/pytest-lsp/hatch.toml b/lib/pytest-lsp/hatch.toml new file mode 100644 index 0000000..5951ee0 --- /dev/null +++ b/lib/pytest-lsp/hatch.toml @@ -0,0 +1,9 @@ +[version] +path = "pytest_lsp/client.py" +validate-bump = false + +[build.targets.sdist] +include = ["pytest_lsp", "tests", "CHANGES.rst"] + +[build.targets.wheel] +packages = ["pytest_lsp"] diff --git a/lib/pytest-lsp/pyproject.toml b/lib/pytest-lsp/pyproject.toml index da51c6d..4852a7c 100644 --- a/lib/pytest-lsp/pyproject.toml +++ b/lib/pytest-lsp/pyproject.toml @@ -1,11 +1,11 @@ [build-system] -requires = ["setuptools >= 61.0.0"] -build-backend = "setuptools.build_meta" +requires = ["hatchling>=1.17.1"] +build-backend = "hatchling.build" [project] name = "pytest-lsp" -version = "0.3.1" -description = "pytest plugin for end-to-end testing of language servers" +dynamic = ["version"] +description = "A pytest plugin for end-to-end testing of language servers" readme = "README.md" requires-python = ">=3.8" license = { text = "MIT" } @@ -39,9 +39,6 @@ dependencies = [ [project.entry-points.pytest11] pytest-lsp = "pytest_lsp" -[tool.setuptools.packages.find] -include = ["pytest_lsp*"] - [tool.coverage.run] source_pkgs = ["pytest_lsp"] From d82d615f0c7bf565c01b87533a7b3087528fca98 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 23:17:23 +0000 Subject: [PATCH 43/50] workflow: Use make_release.py script --- scripts/make-release.sh | 130 ------------------- scripts/make_release.py | 268 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+), 130 deletions(-) delete mode 100755 scripts/make-release.sh create mode 100755 scripts/make_release.py diff --git a/scripts/make-release.sh b/scripts/make-release.sh deleted file mode 100755 index d7f5108..0000000 --- a/scripts/make-release.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/bash -# Book keeping around making a release. This script will -# -# - Call bumpversion to generate a new version based on the changelog -# - Commit, tag and push the new version number. -# - Export the tag name and release date for use later on in the pipeline. -set -e - -SRC= -TAG_PREFIX= -COMMIT_MSG= - - -COMPONENT=$1 -case $1 in - lsp-devtools) - SRC="lib/lsp-devtools" - TAG_PREFIX="lsp-devtools-v" - COMMIT_MSG="lsp-devtools v" - ;; - pytest-lsp) - SRC="lib/pytest-lsp" - TAG_PREFIX="pytest-lsp-v" - COMMIT_MSG="pytest-lsp v" - ;; - *) - echo "Unkown component ${1}" - exit 1 - ;; -esac - -if [ -z "${SRC}" ]; then - echo "SRC dir is not set!" - exit 1 -fi - -if [ -z "${TAG_PREFIX}" ]; then - echo "TAG_PREFIX is not set!" - exit 1 -fi - -if [ -z "${COMMIT_MSG}" ]; then - echo "COMMIT_MSG is not set!" - exit 1 -fi - -cd ${SRC} - -# Use the changelog to determine the type of release to make. -if [ ! -z "$(find changes -name '*.breaking.rst')" ]; then - echo "Breaking changes found, doing major release!" - KIND="major" -elif [ ! -z "$(find changes -name '*.feature.rst')" ]; then - echo "New features found, doing minor release!" - KIND="minor" -else - echo "Doing patch release" - KIND="patch" -fi - -# Bump the version accordingly -python -m bumpversion ${KIND} -VERSION=$(grep 'current_version' .bumpversion.cfg | sed 's/.*=\s\(.*\)/\1/') - -# If we're in a PR build, make a dev version number based on it. -if [[ "${GITHUB_REF}" == refs/pull/* ]]; then - - BUILD=$(echo $GITHUB_REF | sed -E 's/.*\/([0-9]+)\/.*/\1/') - - echo - echo "ref: ${GITHUB_REF}" - echo "Current Version: ${VERSION}" - echo "Build number is ${BUILD}" - echo - - # Annoying that this can't be the same... - if [ "${COMPONENT}" = "vscode" ]; then - VERSION="${VERSION}-dev${BUILD}" - else - VERSION="${VERSION}.dev${BUILD}" - fi - - echo "Dev version number is: ${VERSION}" - - python -m bumpversion --allow-dirty --new-version "${VERSION}" dev - -fi - -TAG="${TAG_PREFIX}${VERSION}" -DATE=$(date +%Y-%m-%d) - - -# Only if we are on the release branch. -if [ "${GITHUB_REF}" = "refs/heads/release" ]; then - - # Make sure there's at least some changes... - if [ -z "$(find changes -name '*.rst')" ]; then - echo "There are no changes!" - exit 1 - fi - - # Write the release notes for github - python -m towncrier build --draft --version="${VERSION}" | \ - rst2html.py --template=changes/github-template.html > .changes.html - - # Write the release notes for the changelog - python -m towncrier build --yes --version="${VERSION}" - - # Setup git, commit, tag and push all the changes. - git config user.name github-actions - git config user.email github-actions@github.com - - git commit -am "${COMMIT_MSG}${VERSION}" - - # Other stages may have run before this, make sure we have the latest - git pull --rebase origin release - git tag -a "${TAG}" -m "${COMMIT_MSG}${VERSION}" - - git push origin release - git push origin --tags - - # Create a markdown copy of the Changelog, needed for the VSCode marketplace. - pandoc CHANGES.rst -f rst -t gfm -o CHANGELOG.md - - # Export info that can be picked up in later steps. - echo "VERSION=${VERSION}" >> $GITHUB_ENV - echo "RELEASE_TAG=${TAG}" >> $GITHUB_ENV - echo "RELEASE_DATE=${DATE}" >> $GITHUB_ENV - -fi diff --git a/scripts/make_release.py b/scripts/make_release.py new file mode 100755 index 0000000..82a96e7 --- /dev/null +++ b/scripts/make_release.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python3 +"""Book keeping around making a release. + +This script will +- Generate a new version based on the environment (release, dev etc) and the changelog. +- Commit, tag and push the new version (if it's a release) +- Export the tag name and release date for use later on in the pipeline. +""" +import argparse +import io +import json +import os +import pathlib +import re +import subprocess +import sys +from datetime import datetime +from typing import Dict +from typing import Optional +from typing import TypedDict + +IS_CI = "CI" in os.environ +IS_PR = os.environ.get("GITHUB_REF", "").startswith("refs/pull/") +IS_DEVELOP = os.environ.get("GITHUB_REF", "") == "refs/heads/develop" +IS_RELEASE = os.environ.get("GITHUB_REF", "") == "refs/heads/release" + +ENV = os.environ.get("GITHUB_ENV", "") +STEP_SUMMARY = os.environ.get("GITHUB_STEP_SUMMARY", "") + + +class Output: + """An output destination that can be logged to. + + Used to implement the ``echo "string" >> $OUTPUT`` pattern seen in bash + """ + + def __init__(self, dest: str): + self.dest = dest + self.fp = None + + def __enter__(self): + if not self.dest: + self.fp = io.StringIO() + else: + self.fp = open(self.dest, "a") + + return self + + def __exit__(self, exc_type, exc_value, tb): + if isinstance(self.fp, io.StringIO): + print(f"Captured output:\n{self.fp.getvalue()}") + + self.fp.close() + + def __rrshift__(self, other: str): + """Implements the ```"abc" >> dest`` syntax""" + if not self.fp: + raise ValueError("No destination supplied!") + self.fp.write(f"{other}\n") + + +class Component(TypedDict): + """Represents a releasable component.""" + + name: str + """The name of the component.""" + + bump_breaking: str + """The version bump kind to use when breaking changes are detected.""" + + bump_minor: str + """The version bump kind to use when minor changes are detected.""" + + bump_patch: str + """The version bump kind to use when patch changes are detected.""" + + commit_prefix: str + """The prefix to give to version bump commit messages for this component.""" + + src: str + """The directory containing the component, relative to repo root.""" + + tag_prefix: str + """The prefix to give to tagged versions of this component.""" + + +COMPONENTS: Dict[str, Component] = { + c["name"]: c + for c in [ + Component( + name="pytest-lsp", + bump_breaking="major", + bump_minor="minor", + bump_patch="patch", + commit_prefix="pytest-lsp v", + src="lib/pytest-lsp", + tag_prefix="pytest-lsp-v", + ), + Component( + name="lsp-devtools", + bump_breaking="major", + bump_minor="minor", + bump_patch="patch", + commit_prefix="lsp-devtools v", + src="lib/lsp-devtools", + tag_prefix="lsp-devtools-v", + ), + ] +} + + +def main(component_name: str): + component = COMPONENTS[component_name] + + version = set_version(component) + generate_changelog(component, version) + + tag = commit_and_tag(component, version) + date = datetime.now() + + with Output(ENV) as env: + f"VERSION={version}" >> env + f"RELEASE_DATE={date:%Y-%m-%d}" >> env + f"RELEASE_TAG={tag}" >> env + + +def set_version(component: Component) -> str: + """Set the next version of the given component.""" + + changes = pathlib.Path(component["src"]) / "changes" + + if len(list(changes.glob("*.breaking.*"))) > 0: + print("Breaking changes found, doing major release!") + kind = component["bump_breaking"] + + elif len(list(changes.glob("*.feature.*"))) > 0: + print("New features found, doing minor release!") + kind = component["bump_minor"] + + else: + print("Doing patch release!") + kind = component["bump_patch"] + + run("hatch", "version", kind, cwd=component["src"]) + version = run("hatch", "version", cwd=component["src"], capture=True) + if version is None or len(version) == 0: + print("Unable to get version number!") + sys.exit(1) + + if not IS_PR: + print(f"Next version: {version!r}") + return version + + # Make a dev build number based on the PR number + ref = os.environ["GITHUB_REF"] + print(f"Deriving build number from: {ref!r}") + if not (match := re.match(r".*/([0-9]+)/.*", ref)): + print(f"Unable to extract build number from {ref!r}!") + sys.exit(1) + + sep = "-" if component["name"] == "vscode" else "." + dev_version = f"{version}{sep}dev{match.group(1)}" + run("hatch", "version", dev_version, cwd=component["src"]) + + # Annoying, but necessary since hatch normalises `-` to `.` + if component["name"] == "vscode": + package_json = pathlib.Path(component["src"]) / "package.json" + meta = json.loads(package_json.read_text()) + meta["version"] = dev_version + package_json.write_text(json.dumps(meta, indent=2)) + + print(f"Next version: {dev_version!r}") + return dev_version + + +def generate_changelog(component: Component, version: str): + """Generate the changelog for the release.""" + + changes = pathlib.Path(component["src"]) / "changes" + if IS_RELEASE and len(list(changes.glob("*.md"))) == 0: + print("No changes detected, aborting") + sys.exit(1) + + draft = run( + *["towncrier", "build", "--draft", f"--version={version}"], + cwd=component["src"], + capture=True, + ) + if draft is None or len(draft) == 0: + print("Unable to get changelog!") + sys.exit(1) + + draft_file = pathlib.Path(component["src"]) / ".changes.html" + draft_file.write_text(draft) + + with Output(STEP_SUMMARY) as summary: + f"{draft}\n\n" >> summary + + if not IS_RELEASE: + return + + # Release notes for changelog + run("towncrier", "build", "--yes", f"--version={version}", cwd=component["src"]) + + # Needed for VSCode marketplace + if component["name"] == "vscode": + run( + *["cp", "CHANGES.md", "CHANGELOG.md"], + cwd=component["src"], + ) + + +def commit_and_tag(component: Component, version: str) -> str: + """Commit tag and push the new version.""" + + tag = f"{component['tag_prefix']}{version}" + commit = f"{component['commit_prefix']}{version}" + + if not IS_RELEASE: + return tag + + run("git", "config", "user.name", "github-actions[bot]") + run( + "git", + "config", + "user.email", + "41898282+github-actions[bot]@users.noreply.github.com", + ) + run("git", "commit", "-am", commit, cwd=component["src"]) + + # Other releases may have run before this, ensure that we're on the latest. + run("git", "pull", "--rebase", "origin", "release", cwd=component["src"]) + run("git", "tag", "-a", tag, "-m", commit, cwd=component["src"]) + run("git", "push", "origin", "release", cwd=component["src"]) + run("git", "push", "origin", "tags", cwd=component["src"]) + + return tag + + +def run(*cmd, cwd: Optional[str] = None, capture: bool = False) -> Optional[str]: + """Run a command""" + + result = subprocess.run(cmd, cwd=cwd, capture_output=capture) + if result.returncode != 0: + if capture: + sys.stdout.buffer.write(result.stdout) + sys.stdout.flush() + sys.stderr.buffer.write(result.stderr) + sys.stderr.flush() + + sys.exit(result.returncode) + + if capture: + return result.stdout.decode("utf8").strip() + + return None + + +cli = argparse.ArgumentParser(description="Make a release") +cli.add_argument( + "component", + help="the component to make a release for.", + choices=COMPONENTS.keys(), +) + +if __name__ == "__main__": + args = cli.parse_args() + main(args.component) From 84f2a19f97b2b88a1c816b9206b703084e7a4d09 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 23:18:01 +0000 Subject: [PATCH 44/50] workflow: Align workflows to use hatch --- .github/workflows/pytest-lsp-pr.yml | 62 +++++++++++++----------- .github/workflows/pytest-lsp-release.yml | 14 ++---- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/.github/workflows/pytest-lsp-pr.yml b/.github/workflows/pytest-lsp-pr.yml index cad5b0c..7b2ff58 100644 --- a/.github/workflows/pytest-lsp-pr.yml +++ b/.github/workflows/pytest-lsp-pr.yml @@ -1,4 +1,4 @@ -name: pytest-lsp PR +name: 'PR: pytest-lsp' on: pull_request: branches: @@ -8,10 +8,38 @@ on: - 'lib/pytest-lsp/**' jobs: - pytest-lsp: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + cache: pip + cache-dependency-path: lib/pytest-lsp/pyproject.toml + + - run: | + python --version + python -m pip install --upgrade pip + python -m pip install --upgrade hatch towncrier + name: Setup Environment + + - run: | + set -e + ./scripts/make_release.py pytest-lsp + name: Set Version + + - uses: hynek/build-and-inspect-python-package@v1 + with: + path: lib/pytest-lsp + + test: name: "Python v${{ matrix.python-version }} -- ${{ matrix.os }}" runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] os: [ubuntu-latest, windows-latest] @@ -22,41 +50,21 @@ jobs: - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} allow-prereleases: true + python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: lib/pytest-lsp/pyproject.toml - run: | python --version python -m pip install --upgrade pip - python -m pip install --upgrade build tox bump2version + python -m pip install --upgrade tox name: Setup Environment - - run: | - set -e - - # Despite the script's name, this is only used to obtain a - # dev version number e.g. v1.2.3-dev4 - ./scripts/make-release.sh pytest-lsp - name: Set Version - if: matrix.python-version == '3.10' && matrix.os == 'ubuntu-latest' - - run: | cd lib/pytest-lsp version=$(echo ${{ matrix.python-version }} | tr -d .) python -m tox run -f "py${version}" shell: bash - name: Test - - - name: Package - run: | - cd lib/pytest-lsp - python -m build - if: always() && matrix.python-version == '3.10' && matrix.os == 'ubuntu-latest' - - - name: 'Upload Artifact' - uses: actions/upload-artifact@v3 - with: - name: 'dist' - path: lib/pytest-lsp/dist - if: always() && matrix.python-version == '3.10' && matrix.os == 'ubuntu-latest' + name: Run Tests diff --git a/.github/workflows/pytest-lsp-release.yml b/.github/workflows/pytest-lsp-release.yml index d671398..4adef9f 100644 --- a/.github/workflows/pytest-lsp-release.yml +++ b/.github/workflows/pytest-lsp-release.yml @@ -19,33 +19,29 @@ jobs: id-token: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.10" - run: | - sudo apt update - sudo apt install pandoc - python --version python -m pip install --upgrade pip - python -m pip install build bump2version towncrier docutils - - name: Install Build Tools + python -m pip install tox hatch towncrier docutils + name: Setup Environment - run: | set -e - ./scripts/make-release.sh pytest-lsp + ./scripts/make_release.py pytest-lsp name: Set Version id: info - name: Package run: | cd lib/pytest-lsp - python -m build + hatch build - name: 'Upload Artifact' uses: actions/upload-artifact@v3 From 0f0cbd0918bb0a1fd3bb5c80209b83c1f28516ea Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sun, 12 Nov 2023 23:31:37 +0000 Subject: [PATCH 45/50] pytest-lsp: Convert changelog to markdown --- docs/conf.py | 1 + docs/pytest-lsp/changelog.md | 5 + docs/pytest-lsp/changelog.rst | 4 - docs/requirements.txt | 1 + lib/pytest-lsp/CHANGES.md | 145 +++++++++++++++++++++++++ lib/pytest-lsp/CHANGES.rst | 199 ---------------------------------- lib/pytest-lsp/hatch.toml | 2 +- lib/pytest-lsp/pyproject.toml | 8 +- 8 files changed, 157 insertions(+), 208 deletions(-) create mode 100644 docs/pytest-lsp/changelog.md delete mode 100644 docs/pytest-lsp/changelog.rst create mode 100644 lib/pytest-lsp/CHANGES.md delete mode 100644 lib/pytest-lsp/CHANGES.rst diff --git a/docs/conf.py b/docs/conf.py index 7a91042..8d4a43d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,6 +29,7 @@ "sphinx.ext.napoleon", "sphinx.ext.intersphinx", # 3rd party extensions + "myst_parser", "sphinx_copybutton", "sphinx_design", # local extensions diff --git a/docs/pytest-lsp/changelog.md b/docs/pytest-lsp/changelog.md new file mode 100644 index 0000000..5ad6ae2 --- /dev/null +++ b/docs/pytest-lsp/changelog.md @@ -0,0 +1,5 @@ +# Changelog + +```{include} ../../lib/pytest-lsp/CHANGES.md +:relative-images: +``` diff --git a/docs/pytest-lsp/changelog.rst b/docs/pytest-lsp/changelog.rst deleted file mode 100644 index 47e836c..0000000 --- a/docs/pytest-lsp/changelog.rst +++ /dev/null @@ -1,4 +0,0 @@ -Changelog -========= - -.. include:: ../../lib/pytest-lsp/CHANGES.rst diff --git a/docs/requirements.txt b/docs/requirements.txt index 8476ae3..09858ad 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,5 +4,6 @@ sphinx sphinx-copybutton sphinx-design furo +myst-parser pygls>=1.1.0 -e lib/pytest-lsp diff --git a/lib/pytest-lsp/CHANGES.md b/lib/pytest-lsp/CHANGES.md new file mode 100644 index 0000000..fc457ec --- /dev/null +++ b/lib/pytest-lsp/CHANGES.md @@ -0,0 +1,145 @@ +## v0.3.1 - 2023-10-06 + +This release includes some minor breaking changes if you were using the lower-level APIs e.g `make_client_server`. + +See [this commit](https://github.com/swyddfa/esbonio/commit/8565add660ad015c989cd3c4a251dede92525997) for a sample migration + +### Enhancements + +- pytest-lsp's `LanguageClient` is now based on the one provided by `pygls`. + The main benefit is that the server connection is now based on an `asyncio.subprocess.Process` removing the need for pytest-lsp to constantly check to see if the server is still running. ([#61](https://github.com/swyddfa/lsp-devtools/issues/61)) +- Fixtures created with the `@pytest_lsp.fixture` decorator can now request additional pytest fixtures ([#71](https://github.com/swyddfa/lsp-devtools/issues/71)) +- It is now possible to set the environment variables that the server under test is launched with. ([#72](https://github.com/swyddfa/lsp-devtools/issues/72)) +- It is now possible to test any JSON-RPC based server with `pytest-lsp`. + Note however, this support will only ever extend to managing the client-server connection. ([#73](https://github.com/swyddfa/lsp-devtools/issues/73)) + +### Misc + +- `make_test_client` has been renamed to `make_test_lsp_client` ([#73](https://github.com/swyddfa/lsp-devtools/issues/73)) +- Drop support for Python 3.7, add support for Python 3.12 ([#75](https://github.com/swyddfa/lsp-devtools/issues/75)) + +## v0.3.0 - 2023-05-19 + +### Features + +- `@pytest_lsp.fixture` now supports the `yield` statement, allowing the `client` fixture definition to be responsible for initialising and shutting down the LSP session granting the test author full control over the contents of the `initialize` request. + + This is a breaking change, see the documentation for details and [this PR](https://github.com/swyddfa/esbonio/pull/571) for an example migration. ([#47](https://github.com/swyddfa/lsp-devtools/issues/47)) + +- If a client's capabilities has been set, pytest-lsp will automatically check the server's response to see if it is compatible with the capabilities the client provided. + + If an issue is detected, pytest-lsp will emit an `LspSpecificationWarning` + + **Note:** This relies on a dedicated `check_xxx` function being written for each request so only a subset of the LSP spec is currently supported. ([#57](https://github.com/swyddfa/lsp-devtools/issues/57)) + +### Docs + +- Add getting started guide ([#47](https://github.com/swyddfa/lsp-devtools/issues/47)) +- Add note on redefining the `event_loop` fixture to match the client fixture's scope ([#49](https://github.com/swyddfa/lsp-devtools/issues/49)) +- Add documentation on the built in features of the test LSP client ([#50](https://github.com/swyddfa/lsp-devtools/issues/50)) +- Add example on using parameterised fixtures to test with multiple clients ([#51](https://github.com/swyddfa/lsp-devtools/issues/51)) + +### Misc + +- The client-server connection is now managed by a single asyncio event loop, rather than spinning up multiple threads, resulting in a much simpler architecture. ([#44](https://github.com/swyddfa/lsp-devtools/issues/44)) + +### Removed + +- Helper methods like `completion_request` and `notify_did_open` have been removed. + The equivalent methods provided by the LSP specification like `text_document_completion_async` and `text_document_did_open` should be used directly. + + See [this PR](https://github.com/swyddfa/esbonio/pull/571) for an example migration. ([#56](https://github.com/swyddfa/lsp-devtools/issues/56)) + +## v0.2.1 - 2023-01-14 + +### Fixes + +- Ensure that the test client returns a `ShowDocumentResult` for `window/showDocument` requests. ([#34](https://github.com/alcarney/lsp-devtools/issues/34)) + +## v0.2.0 - 2023-01-10 + +### Features + +- The `LanguageClient` now exposes methods covering the full LSP spec thanks to autogenerating its client from type definitions provided by `lsprotocol` ([#25](https://github.com/alcarney/lsp-devtools/issues/25)) + +### Misc + +- Support for Python 3.6 has been dropped. + + Support for Python 3.11 has been added. + + Upgraded to pygls 1.0. ([#25](https://github.com/alcarney/lsp-devtools/issues/25)) + +## v0.1.3 - 2022-10-15 + +### Fixes + +- - Check that server provided for testing doesn't crash within the first 0.1 seconds + - Return `INITIALIZE` response from `ClientServer.start()`. This allows tests to assert against the server's `INITIALIZE` response without resending the `INITIALIZE` request in the actual test. ([#22](https://github.com/alcarney/lsp-devtools/issues/22)) + +## v0.1.2 - 2022-07-18 + +### Enhancements + +- Add helpers for `textDocument/implementation` requests ([#15](https://github.com/alcarney/lsp-devtools/issues/15)) + +## v0.1.1 - 2022-07-17 + +### Misc + +- Remove upper bound on required `pygls` version ([#14](https://github.com/alcarney/lsp-devtools/issues/14)) + +## v0.1.0 - 2022-07-02 + +### Features + +- Any `window/logMessage` messages emitted by a server under test are now captured and reported alongside any test failures ([#5](https://github.com/alcarney/lsp-devtools/issues/5)) + +### Enhancements + +- For currently implemented lsp request helpers, the test client now supports all valid return types. ([#11](https://github.com/alcarney/lsp-devtools/issues/11)) + +### Fixes + +- The test client now correctly handles `null` responses. ([#9](https://github.com/alcarney/lsp-devtools/issues/9)) + +## v0.0.7 - 2022-05-26 + +### Enhancements + +- Add helpers for `textDocument/hover` requests. ([#8](https://github.com/alcarney/lsp-devtools/issues/8)) + +## v0.0.6 - 2022-04-18 + +### Enhancements + +- Added helpers for `textDocument/documentLink` requests. ([#4](https://github.com/alcarney/lsp-devtools/issues/4)) + +## v0.0.5 - 2022-04-02 + +### Fixes + +- The plugin should now work on Python v3.6+ ([#1](https://github.com/alcarney/lsp-devtools/issues/1)) + +## v0.0.3 - 2022-03-28 + +### Removed + +- Removed `event_loop` fixture + +## v0.0.3 - 2022-03-28 + +### Fixes + +- Fixture creation on Python 3.6 should now work + +## v0.0.2 - 2022-03-28 + +### Fixes + +- Ensure the `py.typed` file is packaged. +- The `importlib_resources` import on Python 3.6 should now work + +## v0.0.1 - 2022-03-28 + +Initial Release diff --git a/lib/pytest-lsp/CHANGES.rst b/lib/pytest-lsp/CHANGES.rst deleted file mode 100644 index 91cef4c..0000000 --- a/lib/pytest-lsp/CHANGES.rst +++ /dev/null @@ -1,199 +0,0 @@ -v0.3.1 - 2023-10-06 -------------------- - -This release includes some minor breaking changes if you were using the lower-level APIs e.g ``make_client_server``. - -See `this commit `__ for a sample migration - - -Enhancements -^^^^^^^^^^^^ - -- pytest-lsp's ``LanguageClient`` is now based on the one provided by ``pygls``. - The main benefit is that the server connection is now based on an ``asyncio.subprocess.Process`` removing the need for pytest-lsp to constantly check to see if the server is still running. (`#61 `_) -- Fixtures created with the `@pytest_lsp.fixture` decorator can now request additional pytest fixtures (`#71 `_) -- It is now possible to set the environment variables that the server under test is launched with. (`#72 `_) -- It is now possible to test any JSON-RPC based server with ``pytest-lsp``. - Note however, this support will only ever extend to managing the client-server connection. (`#73 `_) - - -Misc -^^^^ - -- ``make_test_client`` has been renamed to ``make_test_lsp_client`` (`#73 `_) -- Drop support for Python 3.7, add support for Python 3.12 (`#75 `_) - - -v0.3.0 - 2023-05-19 -------------------- - -Features -^^^^^^^^ - -- ``@pytest_lsp.fixture`` now supports the ``yield`` statement, allowing the ``client`` fixture definition to be responsible for initialising and shutting down the LSP session granting the test author full control over the contents of the ``initialize`` request. - - This is a breaking change, see the documentation for details and `this PR `_ for an example migration. (`#47 `_) -- If a client's capabilities has been set, pytest-lsp will automatically check the server's response to see if it is compatible with the capabilities the client provided. - - If an issue is detected, pytest-lsp will emit an ``LspSpecificationWarning`` - - **Note:** This relies on a dedicated ``check_xxx`` function being written for each request so only a subset of the LSP spec is currently supported. (`#57 `_) - - -Docs -^^^^ - -- Add getting started guide (`#47 `_) -- Add note on redefining the ``event_loop`` fixture to match the client fixture's scope (`#49 `_) -- Add documentation on the built in features of the test LSP client (`#50 `_) -- Add example on using parameterised fixtures to test with multiple clients (`#51 `_) - - -Misc -^^^^ - -- The client-server connection is now managed by a single asyncio event loop, rather than spinning up multiple threads, resulting in a much simpler architecture. (`#44 `_) - - -Removed -^^^^^^^ - -- Helper methods like ``completion_request`` and ``notify_did_open`` have been removed. - The equivalent methods provided by the LSP specification like ``text_document_completion_async`` and ``text_document_did_open`` should be used directly. - - See `this PR `_ for an example migration. (`#56 `_) - - -v0.2.1 - 2023-01-14 -------------------- - -Fixes -^^^^^ - -- Ensure that the test client returns a ``ShowDocumentResult`` for ``window/showDocument`` requests. (`#34 `_) - - -v0.2.0 - 2023-01-10 -------------------- - -Features -^^^^^^^^ - -- The ``LanguageClient`` now exposes methods covering the full LSP spec thanks to autogenerating its client from type definitions provided by ``lsprotocol`` (`#25 `_) - - -Misc -^^^^ - -- Support for Python 3.6 has been dropped. - - Support for Python 3.11 has been added. - - Upgraded to pygls 1.0. (`#25 `_) - - -v0.1.3 - 2022-10-15 -------------------- - -Fixes -^^^^^ - -- - Check that server provided for testing doesn't crash within the first 0.1 seconds - - Return `INITIALIZE` response from `ClientServer.start()`. This allows tests to assert against the server's `INITIALIZE` response without resending the `INITIALIZE` request in the actual test. (`#22 `_) - - -v0.1.2 - 2022-07-18 -------------------- - -Enhancements -^^^^^^^^^^^^ - -- Add helpers for ``textDocument/implementation`` requests (`#15 `_) - - -v0.1.1 - 2022-07-17 -------------------- - -Misc -^^^^ - -- Remove upper bound on required ``pygls`` version (`#14 `_) - - -v0.1.0 - 2022-07-02 -------------------- - -Features -^^^^^^^^ - -- Any ``window/logMessage`` messages emitted by a server under test are now captured and reported alongside any test failures (`#5 `_) - - -Enhancements -^^^^^^^^^^^^ - -- For currently implemented lsp request helpers, the test client now supports all valid return types. (`#11 `_) - - -Fixes -^^^^^ - -- The test client now correctly handles ``null`` responses. (`#9 `_) - - -v0.0.7 - 2022-05-26 -------------------- - -Enhancements -^^^^^^^^^^^^ - -- Add helpers for ``textDocument/hover`` requests. (`#8 `_) - - -v0.0.6 - 2022-04-18 -------------------- - -Enhancements -^^^^^^^^^^^^ - -- Added helpers for ``textDocument/documentLink`` requests. (`#4 `_) - - -v0.0.5 - 2022-04-02 -------------------- - -Fixes -^^^^^ - -- The plugin should now work on Python v3.6+ (`#1 `_) - - -v0.0.3 - 2022-03-28 -------------------- - -Removed -^^^^^^^ - -- Removed ``event_loop`` fixture - -v0.0.3 - 2022-03-28 -------------------- - -Fixes -^^^^^ - -- Fixture creation on Python 3.6 should now work - -v0.0.2 - 2022-03-28 --------------------- - -Fixes -^^^^^ - -- Ensure the ``py.typed`` file is packaged. -- The ``importlib_resources`` import on Python 3.6 should now work - -v0.0.1 - 2022-03-28 --------------------- - -Initial Release diff --git a/lib/pytest-lsp/hatch.toml b/lib/pytest-lsp/hatch.toml index 5951ee0..63b7586 100644 --- a/lib/pytest-lsp/hatch.toml +++ b/lib/pytest-lsp/hatch.toml @@ -3,7 +3,7 @@ path = "pytest_lsp/client.py" validate-bump = false [build.targets.sdist] -include = ["pytest_lsp", "tests", "CHANGES.rst"] +include = ["pytest_lsp", "tests", "CHANGES.md"] [build.targets.wheel] packages = ["pytest_lsp"] diff --git a/lib/pytest-lsp/pyproject.toml b/lib/pytest-lsp/pyproject.toml index 4852a7c..9313f68 100644 --- a/lib/pytest-lsp/pyproject.toml +++ b/lib/pytest-lsp/pyproject.toml @@ -55,11 +55,11 @@ profile = "black" asyncio_mode = "auto" [tool.towncrier] -filename = "CHANGES.rst" +filename = "CHANGES.md" directory = "changes/" -title_format = "v{version} - {project_date}" -issue_format = "`#{issue} `_" -underlines = ["-", "^", "\""] +title_format = "## v{version} - {project_date}" +issue_format = "[#{issue}](https://github.com/swyddfa/lsp-devtools/issues/{issue})" +underlines = ["", "", ""] type = [ { name = "Features", directory = "feature", showcontent = true }, From e1d6f89c6c833aed78712740296629ffd88de143 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 13 Nov 2023 19:14:48 +0000 Subject: [PATCH 46/50] lsp-devtools: Remove prometheus code --- .../lsp_devtools/handlers/prometheus.py | 49 ------------------- lib/lsp-devtools/pyproject.toml | 1 - 2 files changed, 50 deletions(-) delete mode 100644 lib/lsp-devtools/lsp_devtools/handlers/prometheus.py diff --git a/lib/lsp-devtools/lsp_devtools/handlers/prometheus.py b/lib/lsp-devtools/lsp_devtools/handlers/prometheus.py deleted file mode 100644 index 7ec665c..0000000 --- a/lib/lsp-devtools/lsp_devtools/handlers/prometheus.py +++ /dev/null @@ -1,49 +0,0 @@ -from prometheus_client import Counter # type: ignore -from prometheus_client import Histogram # type: ignore -from prometheus_client import start_http_server # type: ignore - -from lsp_devtools.handlers import LspHandler -from lsp_devtools.handlers import LspMessage - -REQUESTS_COUNTER = Counter( - "lsp_request_count", "Number of requests sent.", ["session", "source", "method"] -) -REQUESTS_DURATION = Histogram( - "lsp_request_duration", - "Time it takes to process a request", - ["session", "source", "method"], -) -NOTIFICATIONS_COUNTER = Counter( - "lsp_notification_count", - "Number of notification sent.", - ["session", "source", "method"], -) - - -class PrometheusHandler(LspHandler): - """Logging handler that exports metrics to prometheus.""" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - start_http_server(8010) - - self.pending_requests = {} - - def handle_message(self, message: LspMessage): - if message.is_request: - REQUESTS_COUNTER.labels( - message.session, message.source, message.method - ).inc() - self.pending_requests[message.id] = message - - if message.is_response: - request = self.pending_requests.get(message.id, None) - if request: - REQUESTS_DURATION.labels( - request.session, request.source, request.method - ).observe(message.timestamp - request.timestamp) - - if message.is_notification: - NOTIFICATIONS_COUNTER.labels( - message.session, message.source, message.method - ).inc() diff --git a/lib/lsp-devtools/pyproject.toml b/lib/lsp-devtools/pyproject.toml index 4e88cc5..fc1aac7 100644 --- a/lib/lsp-devtools/pyproject.toml +++ b/lib/lsp-devtools/pyproject.toml @@ -49,7 +49,6 @@ typecheck=[ "importlib_resources", "types-setuptools", ] -prometheus = ["prometheus_client"] [project.scripts] lsp-devtools = "lsp_devtools.cli:main" From 209023ebef467297a6abd87e10d3f4dd5d77dc9f Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 13 Nov 2023 19:20:30 +0000 Subject: [PATCH 47/50] lsp-devtools: Use hatch for packaging --- lib/lsp-devtools/hatch.toml | 9 +++++++++ lib/lsp-devtools/pyproject.toml | 22 +++------------------- 2 files changed, 12 insertions(+), 19 deletions(-) create mode 100644 lib/lsp-devtools/hatch.toml diff --git a/lib/lsp-devtools/hatch.toml b/lib/lsp-devtools/hatch.toml new file mode 100644 index 0000000..bca7f16 --- /dev/null +++ b/lib/lsp-devtools/hatch.toml @@ -0,0 +1,9 @@ +[version] +path = "lsp_devtools/__init__.py" +validate-bump = false + +[build.targets.sdist] +include = ["lsp_devtools", "tests", "CHANGES.rst"] + +[build.targets.wheel] +packages = ["lsp_devtools"] diff --git a/lib/lsp-devtools/pyproject.toml b/lib/lsp-devtools/pyproject.toml index fc1aac7..42b1d71 100644 --- a/lib/lsp-devtools/pyproject.toml +++ b/lib/lsp-devtools/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -requires = ["setuptools >= 61.0.0"] -build-backend = "setuptools.build_meta" +requires = ["hatchling>=1.17.1"] +build-backend = "hatchling.build" [project] name = "lsp-devtools" -version = "0.2.0" +dynamic = ["version"] description = "Developer tooling for language servers" readme = "README.md" requires-python = ">=3.8" @@ -37,25 +37,9 @@ dependencies = [ "Documentation" = "https://swyddfa.github.io/lsp-devtools/" "Source Code" = "https://github.com/swyddfa/lsp-devtools" -[project.optional-dependencies] -dev = [ - "black", - "flake8", - "pre-commit", - "tox", -] -typecheck=[ - "mypy", - "importlib_resources", - "types-setuptools", -] - [project.scripts] lsp-devtools = "lsp_devtools.cli:main" -[tool.setuptools.packages.find] -include = ["lsp_devtools*"] - [tool.coverage.run] source_pkgs = ["lsp_devtools"] From d0a7696526243b25c2a5939d7e33d121c7b6dc58 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 13 Nov 2023 19:29:25 +0000 Subject: [PATCH 48/50] workflow: Align workflows to use hatch --- .github/workflows/lsp-devtools-pr.yml | 66 +++++++++++++--------- .github/workflows/lsp-devtools-release.yml | 9 +-- lib/lsp-devtools/tox.ini | 2 +- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/.github/workflows/lsp-devtools-pr.yml b/.github/workflows/lsp-devtools-pr.yml index 70ee63f..b56c517 100644 --- a/.github/workflows/lsp-devtools-pr.yml +++ b/.github/workflows/lsp-devtools-pr.yml @@ -1,4 +1,4 @@ -name: lsp-devtools PR +name: 'PR: lsp-devtools' on: pull_request: branches: @@ -8,12 +8,40 @@ on: - 'lib/lsp-devtools/**' jobs: - lsp-devtools: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + cache: pip + cache-dependency-path: lib/lsp-devtools/pyproject.toml + + - run: | + python --version + python -m pip install --upgrade pip + python -m pip install --upgrade hatch towncrier + name: Setup Environment + + - run: | + set -e + ./scripts/make_release.py lsp-devtools + name: Set Version + + - uses: hynek/build-and-inspect-python-package@v1 + with: + path: lib/lsp-devtools + + test: name: "Python v${{ matrix.python-version }} -- ${{ matrix.os }}" runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] os: [ubuntu-latest] steps: @@ -22,39 +50,21 @@ jobs: - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: + allow-prereleases: true python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: lib/lsp-devtools/pyproject.toml - run: | python --version python -m pip install --upgrade pip - python -m pip install --upgrade build tox bump2version + python -m pip install --upgrade tox name: Setup Environment - - run: | - set -e - - # Despite the script's name, this is only used to obtain a - # dev version number e.g. v1.2.3-dev4 - ./scripts/make-release.sh lsp-devtools - name: Set Version - if: matrix.python-version == '3.10' - - run: | cd lib/lsp-devtools version=$(echo ${{ matrix.python-version }} | tr -d .) - python -m tox -e `tox -l | grep $version | tr '\n' ','` - name: Test - - - name: Package - run: | - cd lib/lsp-devtools - python -m build - if: always() && matrix.python-version == '3.10' - - - name: 'Upload Artifact' - uses: actions/upload-artifact@v3 - with: - name: 'dist' - path: lib/lsp-devtools/dist - if: always() && matrix.python-version == '3.10' + python -m tox run -f "py${version}" + shell: bash + name: Run Tests diff --git a/.github/workflows/lsp-devtools-release.yml b/.github/workflows/lsp-devtools-release.yml index 487aff0..1ba8b84 100644 --- a/.github/workflows/lsp-devtools-release.yml +++ b/.github/workflows/lsp-devtools-release.yml @@ -19,19 +19,16 @@ jobs: id-token: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.10" - run: | - sudo apt update - sudo apt install pandoc - python --version python -m pip install --upgrade pip - python -m pip install build bump2version towncrier docutils + python -m pip install hatch towncrier docutils name: Install Build Tools - run: | @@ -44,7 +41,7 @@ jobs: - name: Package run: | cd lib/lsp-devtools - python -m build + hatch build - name: 'Upload Artifact' uses: actions/upload-artifact@v3 diff --git a/lib/lsp-devtools/tox.ini b/lib/lsp-devtools/tox.ini index 223b1c1..5e5ceda 100644 --- a/lib/lsp-devtools/tox.ini +++ b/lib/lsp-devtools/tox.ini @@ -2,7 +2,7 @@ isolated_build = True skip_missing_interpreters = true min_version = 4.0 -envlist = py{38,39,310,311} +envlist = py{38,39,310,311,312} [testenv] description = "Run lsp-devtools' test suite" From e2b4eb52facef94e0234edeb6c2e181d0cc191e4 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 13 Nov 2023 19:36:39 +0000 Subject: [PATCH 49/50] lsp-devtools: Convert changelog to markdown --- docs/lsp-devtools/changelog.md | 5 ++ docs/lsp-devtools/changelog.rst | 4 -- lib/lsp-devtools/CHANGES.md | 66 +++++++++++++++++++++++++ lib/lsp-devtools/CHANGES.rst | 87 --------------------------------- lib/lsp-devtools/hatch.toml | 2 +- lib/lsp-devtools/pyproject.toml | 8 +-- 6 files changed, 76 insertions(+), 96 deletions(-) create mode 100644 docs/lsp-devtools/changelog.md delete mode 100644 docs/lsp-devtools/changelog.rst create mode 100644 lib/lsp-devtools/CHANGES.md delete mode 100644 lib/lsp-devtools/CHANGES.rst diff --git a/docs/lsp-devtools/changelog.md b/docs/lsp-devtools/changelog.md new file mode 100644 index 0000000..b81666c --- /dev/null +++ b/docs/lsp-devtools/changelog.md @@ -0,0 +1,5 @@ +# Changelog + +```{include} ../../lib/lsp-devtools/CHANGES.md +:relative-images: +``` diff --git a/docs/lsp-devtools/changelog.rst b/docs/lsp-devtools/changelog.rst deleted file mode 100644 index 9327b09..0000000 --- a/docs/lsp-devtools/changelog.rst +++ /dev/null @@ -1,4 +0,0 @@ -Changelog -========= - -.. include:: ../../lib/lsp-devtools/CHANGES.rst diff --git a/lib/lsp-devtools/CHANGES.md b/lib/lsp-devtools/CHANGES.md new file mode 100644 index 0000000..cde8060 --- /dev/null +++ b/lib/lsp-devtools/CHANGES.md @@ -0,0 +1,66 @@ +## v0.2.0 - 2023-10-06 + +### Features + +- **Experimental** Add proof of concept `lsp-devtools client` command that builds on textual's `TextArea` widget to offer an interactive language server client. ([#83](https://github.com/swyddfa/lsp-devtools/issues/83)) + +### Fixes + +- The `lsp-devtools agent` command no longer fails to exit once an LSP session closes. ([#17](https://github.com/swyddfa/lsp-devtools/issues/17)) +- `lsp-devtools record` no longer emits a `ResourceWarning` ([#28](https://github.com/swyddfa/lsp-devtools/issues/28)) +- As a consequence of the new architecture, commands like `lsp-devtools record` no longer miss the start of an LSP session ([#29](https://github.com/swyddfa/lsp-devtools/issues/29)) +- `lsp-devtools agent` no longer emits `Unable to send data, no available transport!` messages ([#38](https://github.com/swyddfa/lsp-devtools/issues/38)) + +### Misc + +- The `lsp-devtools agent` now uses a TCP connection, which should make distribution easier ([#37](https://github.com/swyddfa/lsp-devtools/issues/37)) + +- Drop Python 3.7 support ([#77](https://github.com/swyddfa/lsp-devtools/issues/77)) + +- The `lsp-devtools capabilities` command has been removed in favour of `lsp-devtools record` + + The `lsp-devtools tui` command has been renamed to `lsp-devtools inspect` ([#83](https://github.com/swyddfa/lsp-devtools/issues/83)) + +## v0.1.1 - 2023-01-14 + +### Fixes + +- Fix PyPi packaging ([#33](https://github.com/alcarney/lsp-devtools/issues/33)) + +## v0.1.0 - 2023-01-10 + +### Features + +- Updated `record` command. + + It is now capable of live streaming messages sent between a client and server to stdout, plain text files or a SQLite database. + + It also offers a number of filters for selecting the messages you wish to record, as well as a (WIP!) format string syntax for controlling how messages are formatted. ([#26](https://github.com/alcarney/lsp-devtools/issues/26)) + +- Add `tui` command. + + A proof of concept devtools TUI implemented in textual, that live updates with the LSP messages sent between client and server! + + Requires the server be wrapped in an `agent`. ([#27](https://github.com/alcarney/lsp-devtools/issues/27)) + +### Misc + +- Migrated to `v1.0` ([#26](https://github.com/alcarney/lsp-devtools/issues/26)) + +## v0.0.3 - 2022-07-17 + +### Misc + +- Remove upper bound on required `pygls` version ([#14](https://github.com/alcarney/lsp-devtools/issues/14)) + +## v0.0.2 - 2022-05-06 + +### Fixes + +- Fix `mypy` errors. ([#7](https://github.com/alcarney/lsp-devtools/issues/7)) + +## v0.0.1 - 2022-04-29 + +### Misc + +- Initial release ([#6](https://github.com/alcarney/lsp-devtools/issues/6)) diff --git a/lib/lsp-devtools/CHANGES.rst b/lib/lsp-devtools/CHANGES.rst deleted file mode 100644 index bdc13a8..0000000 --- a/lib/lsp-devtools/CHANGES.rst +++ /dev/null @@ -1,87 +0,0 @@ -v0.2.0 - 2023-10-06 -------------------- - -Features -^^^^^^^^ - -- **Experimental** Add proof of concept ``lsp-devtools client`` command that builds on textual's ``TextArea`` widget to offer an interactive language server client. (`#83 `_) - - -Fixes -^^^^^ - -- The ``lsp-devtools agent`` command no longer fails to exit once an LSP session closes. (`#17 `_) -- ``lsp-devtools record`` no longer emits a ``ResourceWarning`` (`#28 `_) -- As a consequence of the new architecture, commands like ``lsp-devtools record`` no longer miss the start of an LSP session (`#29 `_) -- ``lsp-devtools agent`` no longer emits ``Unable to send data, no available transport!`` messages (`#38 `_) - - -Misc -^^^^ - -- The ``lsp-devtools agent`` now uses a TCP connection, which should make distribution easier (`#37 `_) -- Drop Python 3.7 support (`#77 `_) -- The ``lsp-devtools capabilities`` command has been removed in favour of ``lsp-devtools record`` - - The ``lsp-devtools tui`` command has been renamed to ``lsp-devtools inspect`` (`#83 `_) - - -v0.1.1 - 2023-01-14 -------------------- - -Fixes -^^^^^ - -- Fix PyPi packaging (`#33 `_) - - -v0.1.0 - 2023-01-10 -------------------- - -Features -^^^^^^^^ - -- Updated ``record`` command. - - It is now capable of live streaming messages sent between a client and server to stdout, plain text files or a SQLite database. - - It also offers a number of filters for selecting the messages you wish to record, as well as a (WIP!) format string syntax for controlling how messages are formatted. (`#26 `_) - -- Add ``tui``command. - - A proof of concept devtools TUI implemented in textual, that live updates with the LSP messages sent between client and server! - - Requires the server be wrapped in an ``agent``. (`#27 `_) - - -Misc -^^^^ - -- Migrated to ``v1.0`` (`#26 `_) - - -v0.0.3 - 2022-07-17 -------------------- - -Misc -^^^^ - -- Remove upper bound on required ``pygls`` version (`#14 `_) - - -v0.0.2 - 2022-05-06 -------------------- - -Fixes -^^^^^ - -- Fix ``mypy`` errors. (`#7 `_) - - -v0.0.1 - 2022-04-29 -------------------- - -Misc -^^^^ - -- Initial release (`#6 `_) diff --git a/lib/lsp-devtools/hatch.toml b/lib/lsp-devtools/hatch.toml index bca7f16..ed2660f 100644 --- a/lib/lsp-devtools/hatch.toml +++ b/lib/lsp-devtools/hatch.toml @@ -3,7 +3,7 @@ path = "lsp_devtools/__init__.py" validate-bump = false [build.targets.sdist] -include = ["lsp_devtools", "tests", "CHANGES.rst"] +include = ["lsp_devtools", "tests", "CHANGES.md"] [build.targets.wheel] packages = ["lsp_devtools"] diff --git a/lib/lsp-devtools/pyproject.toml b/lib/lsp-devtools/pyproject.toml index 42b1d71..91f18b2 100644 --- a/lib/lsp-devtools/pyproject.toml +++ b/lib/lsp-devtools/pyproject.toml @@ -53,11 +53,11 @@ force_single_line = true profile = "black" [tool.towncrier] -filename = "CHANGES.rst" +filename = "CHANGES.md" directory = "changes/" -title_format = "v{version} - {project_date}" -issue_format = "`#{issue} `_" -underlines = ["-", "^", "\""] +title_format = "## v{version} - {project_date}" +issue_format = "[#{issue}](https://github.com/swyddfa/lsp-devtools/issues/{issue})" +underlines = ["", "", ""] type = [ { name = "Features", directory = "feature", showcontent = true }, From 6173004edd01af0fd0bb72a26f034ca66f418644 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 18:01:26 +0000 Subject: [PATCH 50/50] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 23.10.1 → 23.11.0](https://github.com/psf/black/compare/23.10.1...23.11.0) - [github.com/pre-commit/mirrors-mypy: v1.6.1 → v1.7.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.6.1...v1.7.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2256e69..95e0e84 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 23.10.1 + rev: 23.11.0 hooks: - id: black exclude: 'lib/pytest-lsp/pytest_lsp/gen.py' @@ -36,7 +36,7 @@ repos: exclude: 'lib/pytest-lsp/pytest_lsp/gen.py' - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.6.1' + rev: 'v1.7.0' hooks: - id: mypy name: mypy (pytest-lsp)