Mirror: TypeScript LSP plugin that finds GraphQL documents in your code and provides diagnostics, auto-complete and hover-information.

add prettier

+4
.husky/pre-commit
···
···
+
#!/usr/bin/env sh
+
. "$(dirname -- "$0")/_/husky.sh"
+
+
pnpm lint-staged
+14 -2
package.json
···
"description": "https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin",
"main": "src/index.js",
"scripts": {
-
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
···
"url": "https://github.com/JoviDeCroock/GraphQLSP/issues"
},
"homepage": "https://github.com/JoviDeCroock/GraphQLSP#readme",
"devDependencies": {
-
"@types/node": "^18.15.11",
"@changesets/cli": "^2.26.1",
"@changesets/get-github-info": "^0.5.2",
"dotenv": "^16.0.3",
"graphql": "^16.5.0",
"typescript": "^5.0.0"
},
"dependencies": {
···
"description": "https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin",
"main": "src/index.js",
"scripts": {
+
"test": "echo \"Error: no test specified\" && exit 1",
+
"prepare": "husky install"
},
"repository": {
"type": "git",
···
"url": "https://github.com/JoviDeCroock/GraphQLSP/issues"
},
"homepage": "https://github.com/JoviDeCroock/GraphQLSP#readme",
+
"prettier": {
+
"singleQuote": true,
+
"arrowParens": "avoid",
+
"trailingComma": "es5"
+
},
+
"lint-staged": {
+
"*.{ts,json,md}": "prettier --write"
+
},
"devDependencies": {
"@changesets/cli": "^2.26.1",
"@changesets/get-github-info": "^0.5.2",
+
"@types/node": "^18.15.11",
"dotenv": "^16.0.3",
"graphql": "^16.5.0",
+
"husky": "^8.0.3",
+
"lint-staged": "^13.2.1",
+
"prettier": "^2.8.7",
"typescript": "^5.0.0"
},
"dependencies": {
+363 -3
pnpm-lock.yaml
···
graphql:
specifier: ^16.5.0
version: 16.5.0
typescript:
specifier: ^5.0.0
version: 5.0.4
···
resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==}
dev: true
/ansi-colors@4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
dev: true
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
/ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'}
···
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
···
/asap@2.0.6:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
dev: false
/auto-bind@4.0.0:
resolution: {integrity: sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==}
···
ansi-styles: 4.3.0
supports-color: 7.2.0
/change-case-all@1.0.15:
resolution: {integrity: sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==}
dependencies:
···
engines: {node: '>=8'}
dev: true
/cliui@6.0.0:
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
dependencies:
···
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
/common-tags@1.8.2:
resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
engines: {node: '>=4.0.0'}
···
which: 1.3.1
dev: true
/csv-generate@3.4.3:
resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==}
dev: true
···
optional: true
dependencies:
ms: 2.1.2
-
dev: false
/decamelize-keys@1.1.1:
resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
···
engines: {node: '>=12'}
dev: true
/electron-to-chromium@1.4.284:
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
dev: false
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
/enquirer@2.3.6:
resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
···
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: true
/extendable-error@0.1.7:
···
has-symbols: 1.0.3
dev: true
/get-symbol-description@1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'}
···
resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==}
dev: true
/iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
···
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
···
call-bind: 1.0.2
dev: true
/is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
···
engines: {node: '>=6'}
dev: true
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
/load-yaml-file@0.2.0:
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
engines: {node: '>=6'}
···
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: false
/loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
···
yargs-parser: 18.1.3
dev: true
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
···
picomatch: 2.3.1
dev: true
/min-indent@1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
···
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
-
dev: false
/no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
···
validate-npm-package-license: 3.0.4
dev: true
/nullthrows@1.1.1:
resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
dev: false
···
wrappy: 1.0.2
dev: false
/os-tmpdir@1.0.2:
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
···
engines: {node: '>=6'}
dev: true
/p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
···
engines: {node: '>=0.10.0'}
dev: false
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
···
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: true
/pify@4.0.1:
···
supports-preserve-symlinks-flag: 1.0.0
dev: true
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
dev: true
/safe-regex-test@1.0.0:
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
dependencies:
···
shebang-regex: 1.0.0
dev: true
/shebang-regex@1.0.0:
resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
engines: {node: '>=0.10.0'}
dev: true
/side-channel@1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
···
engines: {node: '>=8'}
dev: true
/smartwrap@2.0.2:
resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==}
engines: {node: '>=6'}
···
mixme: 0.5.9
dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
···
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
/string.prototype.trim@1.2.7:
resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
···
dependencies:
ansi-regex: 5.0.1
/strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
dev: true
/strip-indent@3.0.0:
···
engines: {node: '>=8'}
dev: true
/title-case@3.0.3:
resolution: {integrity: sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==}
dependencies:
···
/tslib@2.4.1:
resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
-
dev: false
/tty-table@4.2.1:
resolution: {integrity: sha512-xz0uKo+KakCQ+Dxj1D/tKn2FSyreSYWzdkL/BYhgN6oMW808g8QRMuh1atAV9fjTPbWBjfbkKQpI/5rEcnAc7g==}
···
/type-fest@0.13.1:
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
engines: {node: '>=10'}
dev: true
···
isexe: 2.0.0
dev: true
/wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
···
/yallist@2.1.2:
resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
dev: true
/yargs-parser@18.1.3:
···
graphql:
specifier: ^16.5.0
version: 16.5.0
+
husky:
+
specifier: ^8.0.3
+
version: 8.0.3
+
lint-staged:
+
specifier: ^13.2.1
+
version: 13.2.1
+
prettier:
+
specifier: ^2.8.7
+
version: 2.8.7
typescript:
specifier: ^5.0.0
version: 5.0.4
···
resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==}
dev: true
+
/aggregate-error@3.1.0:
+
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
+
engines: {node: '>=8'}
+
dependencies:
+
clean-stack: 2.2.0
+
indent-string: 4.0.0
+
dev: true
+
/ansi-colors@4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
+
dev: true
+
+
/ansi-escapes@4.3.2:
+
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+
engines: {node: '>=8'}
+
dependencies:
+
type-fest: 0.21.3
dev: true
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
+
/ansi-regex@6.0.1:
+
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+
engines: {node: '>=12'}
+
dev: true
+
/ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'}
···
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
+
+
/ansi-styles@6.2.1:
+
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+
engines: {node: '>=12'}
+
dev: true
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
···
/asap@2.0.6:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
dev: false
+
+
/astral-regex@2.0.0:
+
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
+
engines: {node: '>=8'}
+
dev: true
/auto-bind@4.0.0:
resolution: {integrity: sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==}
···
ansi-styles: 4.3.0
supports-color: 7.2.0
+
/chalk@5.2.0:
+
resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==}
+
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
dev: true
+
/change-case-all@1.0.15:
resolution: {integrity: sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==}
dependencies:
···
engines: {node: '>=8'}
dev: true
+
/clean-stack@2.2.0:
+
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
+
engines: {node: '>=6'}
+
dev: true
+
+
/cli-cursor@3.1.0:
+
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
+
engines: {node: '>=8'}
+
dependencies:
+
restore-cursor: 3.1.0
+
dev: true
+
+
/cli-truncate@2.1.0:
+
resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
+
engines: {node: '>=8'}
+
dependencies:
+
slice-ansi: 3.0.0
+
string-width: 4.2.3
+
dev: true
+
+
/cli-truncate@3.1.0:
+
resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
+
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
dependencies:
+
slice-ansi: 5.0.0
+
string-width: 5.1.2
+
dev: true
+
/cliui@6.0.0:
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
dependencies:
···
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
/colorette@2.0.19:
+
resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
+
dev: true
+
+
/commander@10.0.0:
+
resolution: {integrity: sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==}
+
engines: {node: '>=14'}
+
dev: true
+
/common-tags@1.8.2:
resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
engines: {node: '>=4.0.0'}
···
which: 1.3.1
dev: true
+
/cross-spawn@7.0.3:
+
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+
engines: {node: '>= 8'}
+
dependencies:
+
path-key: 3.1.1
+
shebang-command: 2.0.0
+
which: 2.0.2
+
dev: true
+
/csv-generate@3.4.3:
resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==}
dev: true
···
optional: true
dependencies:
ms: 2.1.2
/decamelize-keys@1.1.1:
resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
···
engines: {node: '>=12'}
dev: true
+
/eastasianwidth@0.2.0:
+
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
dev: true
+
/electron-to-chromium@1.4.284:
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
dev: false
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+
/emoji-regex@9.2.2:
+
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
dev: true
/enquirer@2.3.6:
resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
···
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
+
dev: true
+
+
/execa@7.1.1:
+
resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==}
+
engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
+
dependencies:
+
cross-spawn: 7.0.3
+
get-stream: 6.0.1
+
human-signals: 4.3.1
+
is-stream: 3.0.0
+
merge-stream: 2.0.0
+
npm-run-path: 5.1.0
+
onetime: 6.0.0
+
signal-exit: 3.0.7
+
strip-final-newline: 3.0.0
dev: true
/extendable-error@0.1.7:
···
has-symbols: 1.0.3
dev: true
+
/get-stream@6.0.1:
+
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+
engines: {node: '>=10'}
+
dev: true
+
/get-symbol-description@1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'}
···
resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==}
dev: true
+
/human-signals@4.3.1:
+
resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
+
engines: {node: '>=14.18.0'}
+
dev: true
+
+
/husky@8.0.3:
+
resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==}
+
engines: {node: '>=14'}
+
hasBin: true
+
dev: true
+
/iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
···
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
+
/is-fullwidth-code-point@4.0.0:
+
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
+
engines: {node: '>=12'}
+
dev: true
+
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
···
call-bind: 1.0.2
dev: true
+
/is-stream@3.0.0:
+
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
dev: true
+
/is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
···
engines: {node: '>=6'}
dev: true
+
/lilconfig@2.1.0:
+
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+
engines: {node: '>=10'}
+
dev: true
+
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
+
/lint-staged@13.2.1:
+
resolution: {integrity: sha512-8gfzinVXoPfga5Dz/ZOn8I2GOhf81Wvs+KwbEXQn/oWZAvCVS2PivrXfVbFJc93zD16uC0neS47RXHIjXKYZQw==}
+
engines: {node: ^14.13.1 || >=16.0.0}
+
hasBin: true
+
dependencies:
+
chalk: 5.2.0
+
cli-truncate: 3.1.0
+
commander: 10.0.0
+
debug: 4.3.4
+
execa: 7.1.1
+
lilconfig: 2.1.0
+
listr2: 5.0.8
+
micromatch: 4.0.5
+
normalize-path: 3.0.0
+
object-inspect: 1.12.3
+
pidtree: 0.6.0
+
string-argv: 0.3.1
+
yaml: 2.2.1
+
transitivePeerDependencies:
+
- enquirer
+
- supports-color
+
dev: true
+
+
/listr2@5.0.8:
+
resolution: {integrity: sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==}
+
engines: {node: ^14.13.1 || >=16.0.0}
+
peerDependencies:
+
enquirer: '>= 2.3.0 < 3'
+
peerDependenciesMeta:
+
enquirer:
+
optional: true
+
dependencies:
+
cli-truncate: 2.1.0
+
colorette: 2.0.19
+
log-update: 4.0.0
+
p-map: 4.0.0
+
rfdc: 1.3.0
+
rxjs: 7.8.0
+
through: 2.3.8
+
wrap-ansi: 7.0.0
+
dev: true
+
/load-yaml-file@0.2.0:
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
engines: {node: '>=6'}
···
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: false
+
/log-update@4.0.0:
+
resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
+
engines: {node: '>=10'}
+
dependencies:
+
ansi-escapes: 4.3.2
+
cli-cursor: 3.1.0
+
slice-ansi: 4.0.0
+
wrap-ansi: 6.2.0
+
dev: true
+
/loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
···
yargs-parser: 18.1.3
dev: true
+
/merge-stream@2.0.0:
+
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
dev: true
+
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
···
picomatch: 2.3.1
dev: true
+
/mimic-fn@2.1.0:
+
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+
engines: {node: '>=6'}
+
dev: true
+
+
/mimic-fn@4.0.0:
+
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+
engines: {node: '>=12'}
+
dev: true
+
/min-indent@1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
···
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
/no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
···
validate-npm-package-license: 3.0.4
dev: true
+
/normalize-path@3.0.0:
+
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+
engines: {node: '>=0.10.0'}
+
dev: true
+
+
/npm-run-path@5.1.0:
+
resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
+
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
dependencies:
+
path-key: 4.0.0
+
dev: true
+
/nullthrows@1.1.1:
resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
dev: false
···
wrappy: 1.0.2
dev: false
+
/onetime@5.1.2:
+
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+
engines: {node: '>=6'}
+
dependencies:
+
mimic-fn: 2.1.0
+
dev: true
+
+
/onetime@6.0.0:
+
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+
engines: {node: '>=12'}
+
dependencies:
+
mimic-fn: 4.0.0
+
dev: true
+
/os-tmpdir@1.0.2:
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
···
engines: {node: '>=6'}
dev: true
+
/p-map@4.0.0:
+
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
+
engines: {node: '>=10'}
+
dependencies:
+
aggregate-error: 3.1.0
+
dev: true
+
/p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
···
engines: {node: '>=0.10.0'}
dev: false
+
/path-key@3.1.1:
+
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+
engines: {node: '>=8'}
+
dev: true
+
+
/path-key@4.0.0:
+
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+
engines: {node: '>=12'}
+
dev: true
+
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
···
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
+
dev: true
+
+
/pidtree@0.6.0:
+
resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
+
engines: {node: '>=0.10'}
+
hasBin: true
dev: true
/pify@4.0.1:
···
supports-preserve-symlinks-flag: 1.0.0
dev: true
+
/restore-cursor@3.1.0:
+
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
+
engines: {node: '>=8'}
+
dependencies:
+
onetime: 5.1.2
+
signal-exit: 3.0.7
+
dev: true
+
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
+
/rfdc@1.3.0:
+
resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
+
dev: true
+
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
dev: true
+
/rxjs@7.8.0:
+
resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==}
+
dependencies:
+
tslib: 2.4.1
+
dev: true
+
/safe-regex-test@1.0.0:
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
dependencies:
···
shebang-regex: 1.0.0
dev: true
+
/shebang-command@2.0.0:
+
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+
engines: {node: '>=8'}
+
dependencies:
+
shebang-regex: 3.0.0
+
dev: true
+
/shebang-regex@1.0.0:
resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
engines: {node: '>=0.10.0'}
dev: true
+
/shebang-regex@3.0.0:
+
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+
engines: {node: '>=8'}
+
dev: true
+
/side-channel@1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
···
engines: {node: '>=8'}
dev: true
+
/slice-ansi@3.0.0:
+
resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
+
engines: {node: '>=8'}
+
dependencies:
+
ansi-styles: 4.3.0
+
astral-regex: 2.0.0
+
is-fullwidth-code-point: 3.0.0
+
dev: true
+
+
/slice-ansi@4.0.0:
+
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
+
engines: {node: '>=10'}
+
dependencies:
+
ansi-styles: 4.3.0
+
astral-regex: 2.0.0
+
is-fullwidth-code-point: 3.0.0
+
dev: true
+
+
/slice-ansi@5.0.0:
+
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
+
engines: {node: '>=12'}
+
dependencies:
+
ansi-styles: 6.2.1
+
is-fullwidth-code-point: 4.0.0
+
dev: true
+
/smartwrap@2.0.2:
resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==}
engines: {node: '>=6'}
···
mixme: 0.5.9
dev: true
+
/string-argv@0.3.1:
+
resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
+
engines: {node: '>=0.6.19'}
+
dev: true
+
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
···
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
+
+
/string-width@5.1.2:
+
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+
engines: {node: '>=12'}
+
dependencies:
+
eastasianwidth: 0.2.0
+
emoji-regex: 9.2.2
+
strip-ansi: 7.0.1
+
dev: true
/string.prototype.trim@1.2.7:
resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
···
dependencies:
ansi-regex: 5.0.1
+
/strip-ansi@7.0.1:
+
resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==}
+
engines: {node: '>=12'}
+
dependencies:
+
ansi-regex: 6.0.1
+
dev: true
+
/strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
+
dev: true
+
+
/strip-final-newline@3.0.0:
+
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+
engines: {node: '>=12'}
dev: true
/strip-indent@3.0.0:
···
engines: {node: '>=8'}
dev: true
+
/through@2.3.8:
+
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+
dev: true
+
/title-case@3.0.3:
resolution: {integrity: sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==}
dependencies:
···
/tslib@2.4.1:
resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
/tty-table@4.2.1:
resolution: {integrity: sha512-xz0uKo+KakCQ+Dxj1D/tKn2FSyreSYWzdkL/BYhgN6oMW808g8QRMuh1atAV9fjTPbWBjfbkKQpI/5rEcnAc7g==}
···
/type-fest@0.13.1:
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
+
engines: {node: '>=10'}
+
dev: true
+
+
/type-fest@0.21.3:
+
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
dev: true
···
isexe: 2.0.0
dev: true
+
/which@2.0.2:
+
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+
engines: {node: '>= 8'}
+
hasBin: true
+
dependencies:
+
isexe: 2.0.0
+
dev: true
+
/wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
···
/yallist@2.1.2:
resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
+
dev: true
+
+
/yaml@2.2.1:
+
resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==}
+
engines: {node: '>= 14'}
dev: true
/yargs-parser@18.1.3:
+6 -4
src/cursor.ts
···
-
import { IPosition } from "graphql-language-service";
export class Cursor implements IPosition {
line: number;
···
}
lessThanOrEqualTo(position: IPosition) {
-
return this.line < position.line ||
-
(this.line === position.line && this.character <= position.character);
}
-
}
···
+
import { IPosition } from 'graphql-language-service';
export class Cursor implements IPosition {
line: number;
···
}
lessThanOrEqualTo(position: IPosition) {
+
return (
+
this.line < position.line ||
+
(this.line === position.line && this.character <= position.character)
+
);
}
+
}
+24 -15
src/getSchema.ts
···
-
import { GraphQLSchema, buildSchema, buildClientSchema } from 'graphql'
-
import path from 'path'
-
import fs from 'fs'
-
export const loadSchema = (root: string, schema: string): { current: GraphQLSchema | null } => {
-
const ref: { current: GraphQLSchema | null } = { current: null }
const isJson = schema.endsWith('json');
-
const resolvedPath = path.resolve(path.dirname(root), schema)
-
const contents = fs.readFileSync(resolvedPath, 'utf-8')
fs.watchFile(resolvedPath, () => {
-
const contents = fs.readFileSync(resolvedPath, 'utf-8')
-
const parsedSchema = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents)
-
ref.current = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents)
-
return ref
-
})
-
ref.current = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents)
-
return ref
-
}
···
+
import { GraphQLSchema, buildSchema, buildClientSchema } from 'graphql';
+
import path from 'path';
+
import fs from 'fs';
+
export const loadSchema = (
+
root: string,
+
schema: string
+
): { current: GraphQLSchema | null } => {
+
const ref: { current: GraphQLSchema | null } = { current: null };
const isJson = schema.endsWith('json');
+
const resolvedPath = path.resolve(path.dirname(root), schema);
+
const contents = fs.readFileSync(resolvedPath, 'utf-8');
fs.watchFile(resolvedPath, () => {
+
const contents = fs.readFileSync(resolvedPath, 'utf-8');
+
const parsedSchema = isJson
+
? buildClientSchema(JSON.parse(contents))
+
: buildSchema(contents);
+
ref.current = isJson
+
? buildClientSchema(JSON.parse(contents))
+
: buildSchema(contents);
+
return ref;
+
});
+
ref.current = isJson
+
? buildClientSchema(JSON.parse(contents))
+
: buildSchema(contents);
+
return ref;
+
};
+218 -142
src/index.ts
···
-
import ts from "typescript/lib/tsserverlibrary";
-
import { isNoSubstitutionTemplateLiteral, ScriptElementKind, isIdentifier, isTaggedTemplateExpression, isToken, isTemplateExpression, isImportTypeNode, ImportTypeNode } from "typescript";
-
import { getHoverInformation, getAutocompleteSuggestions, getDiagnostics, Diagnostic } from 'graphql-language-service'
-
import { parse, Kind, FragmentDefinitionNode, OperationDefinitionNode } from 'graphql'
import fs from 'fs';
-
import { Cursor } from "./cursor";
-
import { loadSchema } from "./getSchema";
-
import { getToken } from "./token";
-
import { findAllTaggedTemplateNodes, findNode, getSource } from "./utils";
-
import { resolveTemplate } from "./resolve";
-
import { generateTypedDocumentNodes } from "./types/generate";
function createBasicDecorator(info: ts.server.PluginCreateInfo) {
const proxy: ts.LanguageService = Object.create(null);
-
for (let k of Object.keys(info.languageService) as Array<keyof ts.LanguageService>) {
const x = info.languageService[k]!;
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
proxy[k] = (...args: Array<{}>) => x.apply(info.languageService, args);
···
}
function create(info: ts.server.PluginCreateInfo) {
-
const logger = (msg: string) => info.project.projectService.logger.info(`[ts-graphql-plugin] ${msg}`);
logger('config: ' + JSON.stringify(info.config));
if (!info.config.schema) {
throw new Error('Please provide a GraphQL Schema!');
}
-
info.project.projectService.logger.info(
-
"Setting up the GraphQL Plugin"
-
);
const tagTemplate = info.config.template || 'gql';
const scalars = info.config.scalars || {};
···
const schema = loadSchema(info.project.getProjectName(), info.config.schema);
proxy.getSemanticDiagnostics = (filename: string): ts.Diagnostic[] => {
-
const originalDiagnostics = info.languageService.getSemanticDiagnostics(filename)
-
const source = getSource(info, filename)
-
if (!source) return originalDiagnostics
-
const nodes = findAllTaggedTemplateNodes(source)
const texts = nodes.map(node => {
if (isNoSubstitutionTemplateLiteral(node) || isTemplateExpression(node)) {
if (isTaggedTemplateExpression(node.parent)) {
-
node = node.parent
} else {
-
return undefined
}
}
-
return resolveTemplate(node, filename, info)
-
})
-
-
const diagnostics = nodes.map(x => {
-
let node = x;
-
if (isNoSubstitutionTemplateLiteral(node) || isTemplateExpression(node)) {
-
if (isTaggedTemplateExpression(node.parent)) {
-
node = node.parent
-
} else {
-
return undefined
}
-
}
-
const text = resolveTemplate(node, filename, info)
-
const lines = text.split('\n')
-
let startingPosition = node.pos + (tagTemplate.length + 1)
-
const graphQLDiagnostics = getDiagnostics(text, schema.current).map(x => {
-
const { start, end } = x.range;
-
// We add the start.line to account for newline characters which are
-
// split out
-
let startChar = startingPosition + start.line
-
for (let i = 0; i <= start.line; i++) {
-
if (i === start.line) startChar += start.character
-
else startChar += lines[i].length
-
}
-
let endChar = startingPosition + end.line
-
for (let i = 0; i <= end.line; i++) {
-
if (i === end.line) endChar += end.character
-
else endChar += lines[i].length
-
}
-
// We add 1 to the start because the range is exclusive of start.character
-
return { ...x, start: startChar + 1, length: endChar - startChar }
-
})
-
const parsed = parse(text);
-
if (parsed.definitions.some(x => x.kind === Kind.OPERATION_DEFINITION)) {
-
const op = parsed.definitions.find(x => x.kind === Kind.OPERATION_DEFINITION) as OperationDefinitionNode
-
if (!op.name) {
-
graphQLDiagnostics.push({
-
message: 'Operation needs a name for types to be generated.',
-
start: node.pos,
-
length: x.getText().length,
-
range: {} as any,
-
severity: 2,
-
} as any)
}
-
}
-
return graphQLDiagnostics;
-
}).flat().filter(Boolean) as Array<Diagnostic & { length: number; start: number }>
const newDiagnostics = diagnostics.map(diag => {
const result: ts.Diagnostic = {
file: source,
length: diag.length,
start: diag.start,
-
category: diag.severity === 2 ? ts.DiagnosticCategory.Warning : ts.DiagnosticCategory.Error,
code: 51001,
messageText: diag.message.split('\n')[0],
-
}
return result;
-
})
if (!newDiagnostics.length) {
try {
const parts = source.fileName.split('/');
const name = parts[parts.length - 1];
const nameParts = name.split('.');
-
nameParts[nameParts.length - 1] = 'generated.ts'
-
parts[parts.length - 1] = nameParts.join('.')
const contents = fs.readFileSync(filename, 'utf-8');
const currentText = source.getFullText();
-
if (contents !== currentText) {
-
return [
-
...newDiagnostics,
-
...originalDiagnostics
-
]
}
-
generateTypedDocumentNodes(schema.current, parts.join('/'), texts.join('\n'), scalars).then(() => {
nodes.forEach((node, i) => {
const queryText = texts[i] || '';
const parsed = parse(queryText);
-
const isFragment = parsed.definitions.every(x => x.kind === Kind.FRAGMENT_DEFINITION);
let name = '';
if (isFragment) {
-
const fragmentNode = parsed.definitions[0] as FragmentDefinitionNode;
name = fragmentNode.name.value;
} else {
-
const operationNode = parsed.definitions[0] as OperationDefinitionNode;
name = operationNode.name?.value || '';
}
-
if (!name) return;
-
name = name.charAt(0).toUpperCase() + name.slice(1);
const parentChildren = node.parent.getChildren();
-
const exportName = isFragment ? `${name}FragmentDoc` : `${name}Document`;
-
const imp = ` as typeof import('./${nameParts.join('.').replace('.ts', '')}').${exportName}`;
-
// This checks whether one of the children is an import-type
// which is a short-circuit if there is no as
-
const typeImport = parentChildren.find(x => isImportTypeNode(x)) as ImportTypeNode
if (typeImport && typeImport.getText().includes(exportName)) return;
-
const span = { length: 1, start: node.end };
-
const text = source.text.substring(0, span.start) + imp + source.text.substring(span.start + span.length, source.text.length);
-
const scriptInfo = info.project.projectService.getScriptInfo(filename);
const snapshot = scriptInfo!.getSnapshot();
-
// TODO: potential optimisation is to write only one script-update
-
source.update(text, { span, newLength: imp.length })
scriptInfo!.editContent(0, snapshot.getLength(), text);
info.languageServiceHost.writeFile!(source.fileName, text);
scriptInfo!.registerFileUpdate();
···
// that would be a win. If not we should check if we can figure it out through
// the script-info whether there are unsaved changes and not run this
// scriptInfo!.open(text);
-
})
});
} catch (e) {}
}
-
return [
-
...newDiagnostics,
-
...originalDiagnostics
-
]
-
}
proxy.getCompletionsAtPosition = (
filename: string,
···
isMemberCompletion: false,
isNewIdentifierLocation: false,
entries: [],
-
}
-
-
const source = getSource(info, filename)
-
if (!source) return originalCompletions
-
let node = findNode(source, cursorPosition)
if (!node) return originalCompletions;
-
while (isNoSubstitutionTemplateLiteral(node) || isToken(node) || isTemplateExpression(node)) {
-
node = node.parent
}
if (isTaggedTemplateExpression(node)) {
const { template, tag } = node;
-
if (!isIdentifier(tag) || tag.text !== tagTemplate) return originalCompletions;
-
const text = resolveTemplate(node, filename, info)
-
const foundToken = getToken(template, cursorPosition)
-
if (!foundToken || !schema.current) return originalCompletions
-
const suggestions = getAutocompleteSuggestions(schema.current, text, new Cursor(foundToken.line, foundToken.start))
-
let fragments: Array<FragmentDefinitionNode> = []
try {
const parsed = parse(text);
-
fragments = parsed.definitions.filter(x => x.kind === Kind.FRAGMENT_DEFINITION) as Array<FragmentDefinitionNode>
} catch (e) {}
const result: ts.WithMetadata<ts.CompletionInfo> = {
···
isMemberCompletion: false,
isNewIdentifierLocation: false,
// TODO: check whether we can add descriptions to the entries
-
entries: [...suggestions.map(suggestion => ({
-
kind: ScriptElementKind.variableElement,
-
name: suggestion.label,
-
kindModifiers: 'declare',
-
sortText: suggestion.sortText || '0',
-
})), ...fragments.map(fragment => ({
-
kind: ScriptElementKind.variableElement,
-
name: fragment.name.value,
-
insertText: '...' + fragment.name.value,
-
kindModifiers: 'declare',
-
sortText: '0',
-
})), ...originalCompletions.entries],
-
}
-
return result
} else {
-
return originalCompletions
}
-
}
proxy.getQuickInfoAtPosition = (filename: string, cursorPosition: number) => {
const originalInfo = info.languageService.getQuickInfoAtPosition(
filename,
cursorPosition
-
)
-
-
const source = getSource(info, filename)
-
if (!source) return originalInfo
-
let node = findNode(source, cursorPosition)
if (!node) return originalInfo;
-
while (isNoSubstitutionTemplateLiteral(node) || isToken(node) || isTemplateExpression(node)) {
-
node = node.parent
}
if (isTaggedTemplateExpression(node)) {
const { template, tag } = node;
if (!isIdentifier(tag) || tag.text !== tagTemplate) return originalInfo;
-
const text = resolveTemplate(node, filename, info)
-
const foundToken = getToken(template, cursorPosition)
-
if (!foundToken || !schema.current) return originalInfo
-
const hoverInfo = getHoverInformation(schema.current, text, new Cursor(foundToken.line, foundToken.start))
const result: ts.QuickInfo = {
kind: ts.ScriptElementKind.string,
textSpan: {
start: cursorPosition,
-
length: 1
},
kindModifiers: '',
-
displayParts: Array.isArray(hoverInfo) ? hoverInfo.map(item => ({ kind: '', text: item as string })) : [{ kind: '', text: hoverInfo as string }]
};
return result;
} else {
-
return originalInfo
}
-
}
logger('proxy: ' + JSON.stringify(proxy));
···
+
import ts from 'typescript/lib/tsserverlibrary';
+
import {
+
isNoSubstitutionTemplateLiteral,
+
ScriptElementKind,
+
isIdentifier,
+
isTaggedTemplateExpression,
+
isToken,
+
isTemplateExpression,
+
isImportTypeNode,
+
ImportTypeNode,
+
} from 'typescript';
+
import {
+
getHoverInformation,
+
getAutocompleteSuggestions,
+
getDiagnostics,
+
Diagnostic,
+
} from 'graphql-language-service';
+
import {
+
parse,
+
Kind,
+
FragmentDefinitionNode,
+
OperationDefinitionNode,
+
} from 'graphql';
import fs from 'fs';
+
import { Cursor } from './cursor';
+
import { loadSchema } from './getSchema';
+
import { getToken } from './token';
+
import { findAllTaggedTemplateNodes, findNode, getSource } from './utils';
+
import { resolveTemplate } from './resolve';
+
import { generateTypedDocumentNodes } from './types/generate';
function createBasicDecorator(info: ts.server.PluginCreateInfo) {
const proxy: ts.LanguageService = Object.create(null);
+
for (let k of Object.keys(info.languageService) as Array<
+
keyof ts.LanguageService
+
>) {
const x = info.languageService[k]!;
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
proxy[k] = (...args: Array<{}>) => x.apply(info.languageService, args);
···
}
function create(info: ts.server.PluginCreateInfo) {
+
const logger = (msg: string) =>
+
info.project.projectService.logger.info(`[ts-graphql-plugin] ${msg}`);
logger('config: ' + JSON.stringify(info.config));
if (!info.config.schema) {
throw new Error('Please provide a GraphQL Schema!');
}
+
info.project.projectService.logger.info('Setting up the GraphQL Plugin');
const tagTemplate = info.config.template || 'gql';
const scalars = info.config.scalars || {};
···
const schema = loadSchema(info.project.getProjectName(), info.config.schema);
proxy.getSemanticDiagnostics = (filename: string): ts.Diagnostic[] => {
+
const originalDiagnostics =
+
info.languageService.getSemanticDiagnostics(filename);
+
const source = getSource(info, filename);
+
if (!source) return originalDiagnostics;
+
const nodes = findAllTaggedTemplateNodes(source);
const texts = nodes.map(node => {
if (isNoSubstitutionTemplateLiteral(node) || isTemplateExpression(node)) {
if (isTaggedTemplateExpression(node.parent)) {
+
node = node.parent;
} else {
+
return undefined;
}
}
+
return resolveTemplate(node, filename, info);
+
});
+
const diagnostics = nodes
+
.map(x => {
+
let node = x;
+
if (
+
isNoSubstitutionTemplateLiteral(node) ||
+
isTemplateExpression(node)
+
) {
+
if (isTaggedTemplateExpression(node.parent)) {
+
node = node.parent;
+
} else {
+
return undefined;
+
}
}
+
const text = resolveTemplate(node, filename, info);
+
const lines = text.split('\n');
+
let startingPosition = node.pos + (tagTemplate.length + 1);
+
const graphQLDiagnostics = getDiagnostics(text, schema.current).map(
+
x => {
+
const { start, end } = x.range;
+
// We add the start.line to account for newline characters which are
+
// split out
+
let startChar = startingPosition + start.line;
+
for (let i = 0; i <= start.line; i++) {
+
if (i === start.line) startChar += start.character;
+
else startChar += lines[i].length;
+
}
+
let endChar = startingPosition + end.line;
+
for (let i = 0; i <= end.line; i++) {
+
if (i === end.line) endChar += end.character;
+
else endChar += lines[i].length;
+
}
+
// We add 1 to the start because the range is exclusive of start.character
+
return { ...x, start: startChar + 1, length: endChar - startChar };
+
}
+
);
+
const parsed = parse(text);
+
if (
+
parsed.definitions.some(x => x.kind === Kind.OPERATION_DEFINITION)
+
) {
+
const op = parsed.definitions.find(
+
x => x.kind === Kind.OPERATION_DEFINITION
+
) as OperationDefinitionNode;
+
if (!op.name) {
+
graphQLDiagnostics.push({
+
message: 'Operation needs a name for types to be generated.',
+
start: node.pos,
+
length: x.getText().length,
+
range: {} as any,
+
severity: 2,
+
} as any);
+
}
}
+
return graphQLDiagnostics;
+
})
+
.flat()
+
.filter(Boolean) as Array<Diagnostic & { length: number; start: number }>;
const newDiagnostics = diagnostics.map(diag => {
const result: ts.Diagnostic = {
file: source,
length: diag.length,
start: diag.start,
+
category:
+
diag.severity === 2
+
? ts.DiagnosticCategory.Warning
+
: ts.DiagnosticCategory.Error,
code: 51001,
messageText: diag.message.split('\n')[0],
+
};
return result;
+
});
if (!newDiagnostics.length) {
try {
const parts = source.fileName.split('/');
const name = parts[parts.length - 1];
const nameParts = name.split('.');
+
nameParts[nameParts.length - 1] = 'generated.ts';
+
parts[parts.length - 1] = nameParts.join('.');
const contents = fs.readFileSync(filename, 'utf-8');
const currentText = source.getFullText();
+
if (contents !== currentText) {
+
return [...newDiagnostics, ...originalDiagnostics];
}
+
generateTypedDocumentNodes(
+
schema.current,
+
parts.join('/'),
+
texts.join('\n'),
+
scalars
+
).then(() => {
nodes.forEach((node, i) => {
const queryText = texts[i] || '';
const parsed = parse(queryText);
+
const isFragment = parsed.definitions.every(
+
x => x.kind === Kind.FRAGMENT_DEFINITION
+
);
let name = '';
if (isFragment) {
+
const fragmentNode = parsed
+
.definitions[0] as FragmentDefinitionNode;
name = fragmentNode.name.value;
} else {
+
const operationNode = parsed
+
.definitions[0] as OperationDefinitionNode;
name = operationNode.name?.value || '';
}
+
if (!name) return;
+
name = name.charAt(0).toUpperCase() + name.slice(1);
const parentChildren = node.parent.getChildren();
+
const exportName = isFragment
+
? `${name}FragmentDoc`
+
: `${name}Document`;
+
const imp = ` as typeof import('./${nameParts
+
.join('.')
+
.replace('.ts', '')}').${exportName}`;
+
// This checks whether one of the children is an import-type
// which is a short-circuit if there is no as
+
const typeImport = parentChildren.find(x =>
+
isImportTypeNode(x)
+
) as ImportTypeNode;
if (typeImport && typeImport.getText().includes(exportName)) return;
+
const span = { length: 1, start: node.end };
+
const text =
+
source.text.substring(0, span.start) +
+
imp +
+
source.text.substring(
+
span.start + span.length,
+
source.text.length
+
);
+
const scriptInfo =
+
info.project.projectService.getScriptInfo(filename);
const snapshot = scriptInfo!.getSnapshot();
+
// TODO: potential optimisation is to write only one script-update
+
source.update(text, { span, newLength: imp.length });
scriptInfo!.editContent(0, snapshot.getLength(), text);
info.languageServiceHost.writeFile!(source.fileName, text);
scriptInfo!.registerFileUpdate();
···
// that would be a win. If not we should check if we can figure it out through
// the script-info whether there are unsaved changes and not run this
// scriptInfo!.open(text);
+
});
});
} catch (e) {}
}
+
return [...newDiagnostics, ...originalDiagnostics];
+
};
proxy.getCompletionsAtPosition = (
filename: string,
···
isMemberCompletion: false,
isNewIdentifierLocation: false,
entries: [],
+
};
+
+
const source = getSource(info, filename);
+
if (!source) return originalCompletions;
+
let node = findNode(source, cursorPosition);
if (!node) return originalCompletions;
+
while (
+
isNoSubstitutionTemplateLiteral(node) ||
+
isToken(node) ||
+
isTemplateExpression(node)
+
) {
+
node = node.parent;
}
if (isTaggedTemplateExpression(node)) {
const { template, tag } = node;
+
if (!isIdentifier(tag) || tag.text !== tagTemplate)
+
return originalCompletions;
+
const text = resolveTemplate(node, filename, info);
+
const foundToken = getToken(template, cursorPosition);
+
if (!foundToken || !schema.current) return originalCompletions;
+
const suggestions = getAutocompleteSuggestions(
+
schema.current,
+
text,
+
new Cursor(foundToken.line, foundToken.start)
+
);
+
let fragments: Array<FragmentDefinitionNode> = [];
try {
const parsed = parse(text);
+
fragments = parsed.definitions.filter(
+
x => x.kind === Kind.FRAGMENT_DEFINITION
+
) as Array<FragmentDefinitionNode>;
} catch (e) {}
const result: ts.WithMetadata<ts.CompletionInfo> = {
···
isMemberCompletion: false,
isNewIdentifierLocation: false,
// TODO: check whether we can add descriptions to the entries
+
entries: [
+
...suggestions.map(suggestion => ({
+
kind: ScriptElementKind.variableElement,
+
name: suggestion.label,
+
kindModifiers: 'declare',
+
sortText: suggestion.sortText || '0',
+
})),
+
...fragments.map(fragment => ({
+
kind: ScriptElementKind.variableElement,
+
name: fragment.name.value,
+
insertText: '...' + fragment.name.value,
+
kindModifiers: 'declare',
+
sortText: '0',
+
})),
+
...originalCompletions.entries,
+
],
+
};
+
return result;
} else {
+
return originalCompletions;
}
+
};
proxy.getQuickInfoAtPosition = (filename: string, cursorPosition: number) => {
const originalInfo = info.languageService.getQuickInfoAtPosition(
filename,
cursorPosition
+
);
+
+
const source = getSource(info, filename);
+
if (!source) return originalInfo;
+
let node = findNode(source, cursorPosition);
if (!node) return originalInfo;
+
while (
+
isNoSubstitutionTemplateLiteral(node) ||
+
isToken(node) ||
+
isTemplateExpression(node)
+
) {
+
node = node.parent;
}
if (isTaggedTemplateExpression(node)) {
const { template, tag } = node;
if (!isIdentifier(tag) || tag.text !== tagTemplate) return originalInfo;
+
const text = resolveTemplate(node, filename, info);
+
const foundToken = getToken(template, cursorPosition);
+
if (!foundToken || !schema.current) return originalInfo;
+
const hoverInfo = getHoverInformation(
+
schema.current,
+
text,
+
new Cursor(foundToken.line, foundToken.start)
+
);
const result: ts.QuickInfo = {
kind: ts.ScriptElementKind.string,
textSpan: {
start: cursorPosition,
+
length: 1,
},
kindModifiers: '',
+
displayParts: Array.isArray(hoverInfo)
+
? hoverInfo.map(item => ({ kind: '', text: item as string }))
+
: [{ kind: '', text: hoverInfo as string }],
};
return result;
} else {
+
return originalInfo;
}
+
};
logger('proxy: ' + JSON.stringify(proxy));
+60 -24
src/resolve.ts
···
-
import { isAsExpression, isIdentifier, isNoSubstitutionTemplateLiteral, isTaggedTemplateExpression, NoSubstitutionTemplateLiteral, TaggedTemplateExpression, TemplateExpression, TemplateLiteral } from "typescript";
-
import ts from "typescript/lib/tsserverlibrary";
-
import { findNode, getSource } from "./utils";
-
export function resolveTemplate(node: TaggedTemplateExpression, filename: string, info: ts.server.PluginCreateInfo): string {
-
let templateText = node.template.getText().slice(1, -1)
-
if (isNoSubstitutionTemplateLiteral(node.template) || node.template.templateSpans.length === 0) {
-
return templateText
}
node.template.templateSpans.forEach(span => {
if (isIdentifier(span.expression)) {
-
const definitions = info.languageService.getDefinitionAtPosition(filename, span.expression.getStart());
-
if (!definitions) return
-
const def = definitions[0]
-
const src = getSource(info, def.fileName)
-
if (!src) return
-
const node = findNode(src, def.textSpan.start)
-
if (!node || !node.parent) return
-
const parent = node.parent
if (ts.isVariableDeclaration(parent)) {
-
if (parent.initializer && isTaggedTemplateExpression(parent.initializer)) {
-
const text = resolveTemplate(parent.initializer, def.fileName, info)
-
templateText = templateText.replace('${' + span.expression.escapedText + '}', text)
-
} else if (parent.initializer && isAsExpression(parent.initializer) && isTaggedTemplateExpression(parent.initializer.expression)) {
-
const text = resolveTemplate(parent.initializer.expression, def.fileName, info)
-
templateText = templateText.replace('${' + span.expression.escapedText + '}', text)
}
}
}
-
})
-
return templateText
-
}
···
+
import {
+
isAsExpression,
+
isIdentifier,
+
isNoSubstitutionTemplateLiteral,
+
isTaggedTemplateExpression,
+
NoSubstitutionTemplateLiteral,
+
TaggedTemplateExpression,
+
TemplateExpression,
+
TemplateLiteral,
+
} from 'typescript';
+
import ts from 'typescript/lib/tsserverlibrary';
+
import { findNode, getSource } from './utils';
+
export function resolveTemplate(
+
node: TaggedTemplateExpression,
+
filename: string,
+
info: ts.server.PluginCreateInfo
+
): string {
+
let templateText = node.template.getText().slice(1, -1);
+
if (
+
isNoSubstitutionTemplateLiteral(node.template) ||
+
node.template.templateSpans.length === 0
+
) {
+
return templateText;
}
node.template.templateSpans.forEach(span => {
if (isIdentifier(span.expression)) {
+
const definitions = info.languageService.getDefinitionAtPosition(
+
filename,
+
span.expression.getStart()
+
);
+
if (!definitions) return;
+
const def = definitions[0];
+
const src = getSource(info, def.fileName);
+
if (!src) return;
+
const node = findNode(src, def.textSpan.start);
+
if (!node || !node.parent) return;
+
const parent = node.parent;
if (ts.isVariableDeclaration(parent)) {
+
if (
+
parent.initializer &&
+
isTaggedTemplateExpression(parent.initializer)
+
) {
+
const text = resolveTemplate(parent.initializer, def.fileName, info);
+
templateText = templateText.replace(
+
'${' + span.expression.escapedText + '}',
+
text
+
);
+
} else if (
+
parent.initializer &&
+
isAsExpression(parent.initializer) &&
+
isTaggedTemplateExpression(parent.initializer.expression)
+
) {
+
const text = resolveTemplate(
+
parent.initializer.expression,
+
def.fileName,
+
info
+
);
+
templateText = templateText.replace(
+
'${' + span.expression.escapedText + '}',
+
text
+
);
}
}
}
+
});
+
return templateText;
+
}
+21 -14
src/token.ts
···
-
import ts from "typescript/lib/tsserverlibrary";
-
import { onlineParser, State, CharacterStream } from "graphql-language-service";
export interface Token {
start: number;
end: number;
string: string;
-
tokenKind: string
-
line: number
-
state: State
}
-
export const getToken = (template: ts.TemplateLiteral, cursorPosition: number): Token | undefined => {
const text = template.getText().slice(1, -1);
-
const input = text.split('\n')
const parser = onlineParser();
const state = parser.startState();
let cPos = template.pos + 1;
···
const lPos = cPos;
const stream = new CharacterStream(input[i]);
while (!stream.eol()) {
-
const token = parser.token(stream, state)
const string = stream.current();
-
if (string && lPos + stream.getStartOfToken() <= cursorPosition && lPos + stream.getCurrentPosition() >= cursorPosition) {
foundToken = {
line: i,
start: stream.getStartOfToken() + 1,
end: stream.getCurrentPosition(),
string,
state,
-
tokenKind: token
-
}
break;
}
}
-
cPos += input[i].length + 1
}
-
return foundToken
-
}
···
+
import ts from 'typescript/lib/tsserverlibrary';
+
import { onlineParser, State, CharacterStream } from 'graphql-language-service';
export interface Token {
start: number;
end: number;
string: string;
+
tokenKind: string;
+
line: number;
+
state: State;
}
+
export const getToken = (
+
template: ts.TemplateLiteral,
+
cursorPosition: number
+
): Token | undefined => {
const text = template.getText().slice(1, -1);
+
const input = text.split('\n');
const parser = onlineParser();
const state = parser.startState();
let cPos = template.pos + 1;
···
const lPos = cPos;
const stream = new CharacterStream(input[i]);
while (!stream.eol()) {
+
const token = parser.token(stream, state);
const string = stream.current();
+
if (
+
string &&
+
lPos + stream.getStartOfToken() <= cursorPosition &&
+
lPos + stream.getCurrentPosition() >= cursorPosition
+
) {
foundToken = {
line: i,
start: stream.getStartOfToken() + 1,
end: stream.getCurrentPosition(),
string,
state,
+
tokenKind: token,
+
};
break;
}
}
+
cPos += input[i].length + 1;
}
+
return foundToken;
+
};
+52 -47
src/types/generate.ts
···
-
import fs from 'fs'
-
import path from 'path'
-
import { printSchema, parse, GraphQLSchema } from 'graphql'
-
import { codegen } from '@graphql-codegen/core'
-
import * as typescriptPlugin from '@graphql-codegen/typescript'
-
import * as typescriptOperationsPlugin from '@graphql-codegen/typescript-operations'
-
import * as typedDocumentNodePlugin from '@graphql-codegen/typed-document-node'
-
export const generateTypedDocumentNodes = async (schema: GraphQLSchema | null, outputFile: string, doc: string, scalars: Record<string, unknown>) => {
-
if (!schema) return;
-
const config = {
-
documents: [
-
{
-
location: 'operation.graphql',
-
document: parse(doc),
-
},
-
],
-
config: {
-
scalars,
-
// nonOptionalTypename: true,
-
// avoidOptionals, worth looking into
-
enumsAsTypes: true,
-
dedupeOperationSuffix: true,
-
dedupeFragments: true,
-
},
-
// used by a plugin internally, although the 'typescript' plugin currently
-
// returns the string output, rather than writing to a file
-
filename: outputFile,
-
schema: parse(printSchema(schema)),
-
plugins: [
-
// TODO: there's optimisations to be had here where we move the typescript and typescript-operations
-
// to a global __generated__ folder and import from it.
-
{ 'typescript': {} },
-
{ 'typescript-operations': {} },
-
{ 'typed-document-node': {} },
-
],
-
pluginMap: {
-
typescript: typescriptPlugin,
-
'typescript-operations': typescriptOperationsPlugin,
-
'typed-document-node': typedDocumentNodePlugin
-
}
-
}
-
// @ts-ignore
-
const output = await codegen(config)
-
fs.writeFile(path.join(outputFile), output, 'utf8', (err) => {
-
console.error(err)
-
})
-
}
···
+
import fs from 'fs';
+
import path from 'path';
+
import { printSchema, parse, GraphQLSchema } from 'graphql';
+
import { codegen } from '@graphql-codegen/core';
+
import * as typescriptPlugin from '@graphql-codegen/typescript';
+
import * as typescriptOperationsPlugin from '@graphql-codegen/typescript-operations';
+
import * as typedDocumentNodePlugin from '@graphql-codegen/typed-document-node';
+
export const generateTypedDocumentNodes = async (
+
schema: GraphQLSchema | null,
+
outputFile: string,
+
doc: string,
+
scalars: Record<string, unknown>
+
) => {
+
if (!schema) return;
+
const config = {
+
documents: [
+
{
+
location: 'operation.graphql',
+
document: parse(doc),
+
},
+
],
+
config: {
+
scalars,
+
// nonOptionalTypename: true,
+
// avoidOptionals, worth looking into
+
enumsAsTypes: true,
+
dedupeOperationSuffix: true,
+
dedupeFragments: true,
+
},
+
// used by a plugin internally, although the 'typescript' plugin currently
+
// returns the string output, rather than writing to a file
+
filename: outputFile,
+
schema: parse(printSchema(schema)),
+
plugins: [
+
// TODO: there's optimisations to be had here where we move the typescript and typescript-operations
+
// to a global __generated__ folder and import from it.
+
{ typescript: {} },
+
{ 'typescript-operations': {} },
+
{ 'typed-document-node': {} },
+
],
+
pluginMap: {
+
typescript: typescriptPlugin,
+
'typescript-operations': typescriptOperationsPlugin,
+
'typed-document-node': typedDocumentNodePlugin,
+
},
+
};
+
// @ts-ignore
+
const output = await codegen(config);
+
fs.writeFile(path.join(outputFile), output, 'utf8', err => {
+
console.error(err);
+
});
+
};
+23 -10
src/utils.ts
···
-
import ts from "typescript/lib/tsserverlibrary";
-
import { isNoSubstitutionTemplateLiteral, isTaggedTemplateExpression } from "typescript";
-
export function findNode(sourceFile: ts.SourceFile, position: number): ts.Node | undefined {
function find(node: ts.Node): ts.Node | undefined {
if (position >= node.getStart() && position < node.getEnd()) {
return ts.forEachChild(node, find) || node;
···
return find(sourceFile);
}
-
export function findAllTaggedTemplateNodes(sourceFile: ts.SourceFile): Array<ts.TaggedTemplateExpression | ts.NoSubstitutionTemplateLiteral> {
-
const result: Array<ts.TaggedTemplateExpression | ts.NoSubstitutionTemplateLiteral> = [];
function find(node: ts.Node) {
-
if (isTaggedTemplateExpression(node) || isNoSubstitutionTemplateLiteral(node)) {
result.push(node);
return;
} else {
···
export function getSource(info: ts.server.PluginCreateInfo, filename: string) {
const program = info.languageService.getProgram();
-
if (!program) return undefined
-
const source = program.getSourceFile(filename)
-
if (!source) return undefined
-
return source
}
···
+
import ts from 'typescript/lib/tsserverlibrary';
+
import {
+
isNoSubstitutionTemplateLiteral,
+
isTaggedTemplateExpression,
+
} from 'typescript';
+
export function findNode(
+
sourceFile: ts.SourceFile,
+
position: number
+
): ts.Node | undefined {
function find(node: ts.Node): ts.Node | undefined {
if (position >= node.getStart() && position < node.getEnd()) {
return ts.forEachChild(node, find) || node;
···
return find(sourceFile);
}
+
export function findAllTaggedTemplateNodes(
+
sourceFile: ts.SourceFile
+
): Array<ts.TaggedTemplateExpression | ts.NoSubstitutionTemplateLiteral> {
+
const result: Array<
+
ts.TaggedTemplateExpression | ts.NoSubstitutionTemplateLiteral
+
> = [];
function find(node: ts.Node) {
+
if (
+
isTaggedTemplateExpression(node) ||
+
isNoSubstitutionTemplateLiteral(node)
+
) {
result.push(node);
return;
} else {
···
export function getSource(info: ts.server.PluginCreateInfo, filename: string) {
const program = info.languageService.getProgram();
+
if (!program) return undefined;
+
const source = program.getSourceFile(filename);
+
if (!source) return undefined;
+
return source;
}