{"_id":"@vuedx/typescript-plugin-vue","_rev":"177-4078ca57d1b5ecaafe279a0c7cadc0b4","name":"@vuedx/typescript-plugin-vue","dist-tags":{"pnpm-temp":"0.2.3","latest":"0.7.6","insiders":"0.7.5-insiders-1630604709.0","next":"0.7.7-next-1667939290.0"},"versions":{"0.1.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","module":"dist/typescript-plugin-vue.esm.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"typescript":"^3.8.3"},"dependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-wkEzsxIjQXXckU6dVojJTOUQC1d/sNrIo7CWm9U9oM0pzHUZJ697Izw75jcy9paxqBdhxrSE9NPNiode0rjNpw==","shasum":"0eb25a5d546087d3ceee2f628d7fa4ad27ec25ac","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0.tgz","fileCount":7,"unpackedSize":170159,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeeM59CRA9TVsSAnZWagAA1V4P/02lVDlKf5v0t5V5jFaN\nmbRN5I14SfFdPeMqLh2EH8O1pjTgBswqtdA2wFY5OCrPLwaIkvQOu8dJzXH9\nvPnPYxD0nYTtdx+auNPREb9D+/ZdBm5UPlCkUGNWUMX6y5iNoOTE5LiI8dg7\nU591UFFvcrUijvFPU7ihG5HVcp2gZVERvP9gECU+wAwLtxtV65CIxhA7U5Cu\nsY9Y3KiNdIjrqnRPQLVXFHmQd8qUhy069x+d0ST5Zy1Fwai+IqUkFyhg3HnO\nUNULtgyglq0I96m7ePiILWPvOHHoTN5UhtpdMkWYu27P+yh2Eo9E+G+vGrMj\nVHECtFeCSd1u131PgeEE5w8CfHMGwoOL58zYzsYgFUrQchi32mcOVNsuqLSh\nQi19NJWFqnHm7yWIckgecxhbqMqp+jDVCWbGCXztwe7BDd+7NMxqoe2ClwEj\ngu1IWmG9rTl8HKAJoe8a9jtq5Q8IQg8SaQq/VliOcuhQtmSnqbqaG4Lt04Gj\nRRkPU1oQgvgaxnQAUZ44c9UF+hx8Tc/VSw00pg7cIAxi23BAR1cw4Ghgo2yW\nRKOt1mYBB2WCtEsfW2hdAkv9vInRcQb4DQtT5RszfNraH9ylJALc0tNz5I5z\ndhTS7gOYPDptQMFXA7MzuN0TeR+KVZlM5FbpLUxjBem8na58/6vAGUDynnlw\nReLB\r\n=SEL2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE0xcNLV0iWe2HFRUOaU8TksUWRSuPDvFXEtnfjs7Yk+AiEAvSu93Xa6FUpaP52yEji+INcRx6lCiBEe7+S7LN89q8E="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0_1584975484909_0.008674449135264828"},"_hasShrinkwrap":false},"0.1.0-alpha.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.0","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"typescript":"^3.8.3"},"dependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.0","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-fQhcamY/3TwzYXpoWUOJiOHWa2VvoVKIKw/VgElvfIWgccV0P7ZnhOoEhvhGs60v9X6YqujX2uAD7+GYbmw+YQ==","shasum":"f0cd85b5a82c613d822e60640767b8434f07119f","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.0.tgz","fileCount":4,"unpackedSize":83089,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejwVeCRA9TVsSAnZWagAACOUP/RoBv2OL7rLY63FPWts7\nCo42YZrjdkyqsh+JnxzchkGsjztWsLhT2/DTRGgwh82gVKw3lyYsqfT67U/u\nZ/ztHnawYN4XVdVVSJsOOG/DZt0WKnnNaVAxi2lZZ+qZw3Ce03y0ZyPFwwDG\nsagRxrQfkuNOkBBhOtfrDP+rT7BAwHKdyNeOFFSAAjt5V6U2plh4zo3r1lvy\ntVlYtLn7wv5PoVafi/8kE5PZGI/rEYEtqERcSUZ6JHAaaoykkwUo0Ir+OF10\nDtAxjFgpThpCubpfd+AQ31fW9Zqj4HOCu0uJ+tlKzCbsoPLhQcwZEwDfBTVh\nSLCqMqB2D9bL6R8X8mnqDGAVeVPKrIXvBNvgykNFFRB+XhsLmnbCXkwo10sA\ndabHEzTY3dpeFHvb2EHVXJPs39TVS6u/Syv0tZ92heTwPH0xJ9UiGUpqkJKZ\nOQjNuL0Hi+OmAwYIgLYG1kBJ0e/QbWIt1TPuRKhofvflrfqvQpCLU+nJDfcG\n3EhDFMFjOd6qmYVfHjN0gKgE29V9sr7m2EPR6TTjr00PszBwyCfLX+WY3Mqz\nCVcCyJoNc/mjmZUf3IQwdXvbkzuZLmldtMRpNsKThlSxL47H6VN/oTL6hRhg\ng2k+ML2444ZWz1fCObLgFQAISYCkWVrKp0xaM4djfnDxM0isAksdzVvMoKtL\nXPFR\r\n=jErR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCYu6tvNej/FTzCvaAJVLR9JN5DPD64l+Cqu+UxjdQkqAIgRAq+/QRyQ3kcG+Qgs+lHCiDxNIpxhTfA8weYc6rhPAI="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.0_1586431326124_0.21954297279801316"},"_hasShrinkwrap":false},"0.1.0-alpha.1":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.1","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.1","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.1","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-1bTJwW1NdszbIXuHe6qkMZmuHmAoGaT8z1uXvDGZHDt1KQA5DWkIp7hcgHHKSRNAMCgZmU+E5NI7vXYlOitaow==","shasum":"77d55679481debf4cb22d5efd246632a9833a43e","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.1.tgz","fileCount":5,"unpackedSize":1702615,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJej1N4CRA9TVsSAnZWagAAplwP/0pX9bbu3i2c14A+FyFr\npBM4H/piZx8hNB6pwGPCE7fbVKeKdVAL6uGYbMBKImdgOG3t+rYE+MGSd+EL\nxm33AtISqID/RuaAJLLJZx83EJZ7DQ6vgz3pfH1wjI8itL4Knzw3trj/y3cY\nFFWcDHBjewFpznT1uHMtUwJNN682VUSci7qdhCt7UK1PL4IkCbGcIphl/iDW\nhoW5eOKCQqZ12/MOeNw8k+U+wegNQtCRkL2dTa0SRFq9AbG0u+NSBaubdhzf\nALnrsjEp86n1nyMlZbpfgZskj2Wy3EqBr4nNXIOkDOggFScyY99TEVltwosu\nn/nq7GT/jRDQLfX5t70h3GXGBOp6ANNIPg7lzOh16Ov066WRZsAwYSblYWYf\nLBC+o/7XAdWWnYG3bn/qNyOwOnb0jPzVNLEkkoz8gI3HvzenBjKoy8sRbfp3\nNULGfAi5HzqbLDQD3g1OFJgyENJeag11W+yk7PQo9zQWYZmKxxKtwNqEsFTQ\nfVq5x7DcrIxbjxALXiQO+bhHPshXu4CYzWDX7MPwEoHYEHtIsFhlcjFIP0FR\n5oFSheVfgoAGwAr3PiWLrTmP+rRo077hoP+BcfXSQD3qFIW9q6Ptzc0i5Jbn\nEjvXJEtYmHONxoMJJQFDfBlkZD1rYVEDevKoNDoR6Z668KEguIZXC5S1oSqj\n/R4O\r\n=0+zE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEDa7D2jmVpCVx0FawyItYPinwz3PPURqHmz/yye1JIqAiBuK5J62L9CNXKTZVBojRy8hXsDiKdXTEGaDb0uDKTWzw=="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.1_1586451319830_0.2034307395122923"},"_hasShrinkwrap":false},"0.1.0-alpha.2":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.2","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.2","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.2","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-8N8mTHRMbznmBjah5j1I0lO+fuFTsGIpN0ezhC965cVa5WeIASwIe1Ssx1KSdES1IBsDWWDA0QuBhwLgyFnbbA==","shasum":"bb9bffdaf107985915539aff083e3a53d008246f","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.2.tgz","fileCount":5,"unpackedSize":468949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJej4RQCRA9TVsSAnZWagAAnsoP/jTu67dQ534W9zM999nn\n0vbJpmupL5YSaYrVy6emygTfpJQDu9Vo39xZKhpAavuxs53dlxaDq9J/5Q8w\nWtYizzMEbT5cBL6DXe1rApMWrwYz4RCW0sMii2NeanZRqUBJDA8anP56SlXp\nGJsxqQ9J3orHjBeXPWPMuW6xRCd/CKkn3FfWu+W3Z0AA/mJeH/Wvs5WQCFAs\n0NundNw1mVjDRquSt/apHCcZvQq4K1xDE8qqmseWe4ICm51lokLfukbOamNE\nYJYKZXSNvXnDK15LlxTnkhdiY5mTI1qimYjtE1GAk4enmAgIGVEhrCEG8K2f\nq/eEhWniRPd55f9Jk+gGFjtIc+i5sL/dfdoQjLCRMCPiTtnxgPR3Lk7bk67O\nRItvkoE9qjXZHr2dauG+YgEoGu+QUhwhaoeXabOpOKkjwP6fBeC4Qz6hg29B\nNfsfbfOCsOH76ctb/QcVJfdLR+6y209AbOe7vSQaNavawoqsa9y78HW3Yz9t\nRLocpW4pcxtzMX3nFV0XOpGhQUztSnJlCPse9+LErC5nVxxffGEYOCPFQUhH\nnDNQ3jv6PU/SPreD7OmH3PVIQwBBsiCs0YtB6MhuqngunRUltrLNf8RUFgNE\nZIBa9QbdGnUbuF/wKBhSP65Nrukq5ML4EYbX8moBf/5sGT4L5XrZemXKq1Nr\ns/hj\r\n=SDzL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA5DEVZYGzeIVzweZHtHR0ab1d9p7jfe/TW8kRjhjqQqAiEAwZRQ5cgQcYj9S2DEzFF8iZhrh/MHlm+cQBUIvJ7Cmio="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.2_1586463823881_0.09807516550302475"},"_hasShrinkwrap":false},"0.1.0-alpha.3":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.3","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.3","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.3","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-HK9N6YyZE8ZoM3cYbAyq1pMdAw3kMSKqZvbZlcNwSGfcw7JI5n5u36Eo/YkUi6T5JvOSL1vjd9Q0ECXT51J+4A==","shasum":"0bc1041113cb730587ea46800a6cbaef154d4ee7","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.3.tgz","fileCount":5,"unpackedSize":484769,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJekVIeCRA9TVsSAnZWagAAHNwP/3gkcL5pbUJRYVjTq/ew\nc3K733uuzeJ1rWN6hSeZvHVZPX3XTUJ07DJlEWMZ+0P9ZeKAJ/HRn13heSCN\nEgM6cwKk61pW38Z+uLUmDzTJJMW4uccseLQdDf34QK9oMD2BZEXLFIq8k9Ic\nlvsWuH8nr50SLhQU3dOdAmGKN66F/Gg5WtSuxpF6c09bEIBMKT+WqpmLUHK9\nB2HFTzXAzzKMaoPNpHuA9ufGNrS+baxSEvhUuneJaJsugOSwo8Dgg/d6+sSX\nWQgWwCaep5l7baTx/i2LKAzdx4ursY7gIsp8VDsvK12WyFs3cLD6w1KQAodk\nZrI5okdVtbX9MyQY8It/Xd83mY9uWCYoOhOHMCkVyWEXR3mkcQfr4Ghz+DM4\nYfPbJe0H2bGpBBhtdsAzUP7Iltal9KTaeWl4rfr9Zf7SjcsuSF+KqYUJk667\noN8+m2CNCX9Hj4SgTNytben2UxvSFEhKVxqro2Y2SoKTx3wThJykZQ74qHEI\nQAhTnS3eV12GSFZrVU4TRSuUED1QlesbtDAu4dpA/0G6UtQ1/zxDBOl6NfnD\nRDkH9eC4WiJhHeJBegKEqLmBUGRqRH4cTac+6PXmPohommA3TZLDIvx0oSTg\nR3pb5RY9NOfJ/GClxsHF/PMB+rSijayuLtNEu2EcLLUu6eogqOIYIlG77EL/\njJAM\r\n=mQd2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAXs/HP6Y8V5FHNdxRPdFEoYE8wLdAy6qqtDKL+b2XuaAiEA52XomrQAo+SwNuGeh7xmC7NgM9a4MrZc0+ktB+X1Ic8="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.3_1586582046417_0.42016925986046627"},"_hasShrinkwrap":false},"0.1.0-alpha.4":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.4","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.4","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.4","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-dmtr5GWvztyuxCazGBtmIk3jlE/xqekrUn9tCD8YpZCi0/YPlu2c5FLlOYtQ0E8v0yh4hNND0jrgZl/2LKKG/A==","shasum":"3fb57f5fb475ad652a0eb1b938edcd96f74c1ae0","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.4.tgz","fileCount":5,"unpackedSize":530264,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJekXtSCRA9TVsSAnZWagAAdfYP/2Xv9WC6t2VgBvIGSgJe\nW+xvSfsuddB458PtFXENIW1specwJfKmkXv21MQpx8lP1XZK2aClm1D4Jl3b\nFO6huYkgQPeLpJXUtY9RjdehA8x1WO2/UMIvYKpQUcrHs2pFco90VJl9Hw1w\nN4APIhbwHr9/nIffrScBhElYyKqMkrf2dBP2JY6qJYuc0SETZGo6CeDv4cXn\nIP3j99vIkJTTqpaWoVYj9BnZRnDDIxnGo+owQMCkkcdOEjFDSf6U+QoS26zC\nfpCOlMdD/pUs26e8b5/Ooa10REc1ZQETFh5KAQIbrrGm6NZvn7vA+VBJ2BB4\nMsOD4bDltcK1xMhBkDYiQ6/5c3NhZ2tIrU7vZwa8p7y4BDpLI1xC8aVw3jHF\nbWEfVqqaEMUqQHGzmXRx5Pp1vBMG9wxxHqwhWYf0wTo1J9hMetD58VXunDd/\nHciF7JN2rre0hHmya5tRwsb8wtSYXUy9/fBep/vKOftAPlMmRZFa4ygQMYfO\nmgyJgVuD3VCkWFFTqZ8ciRrPCdwuumIMKZSmLnFyLsn/Cx42YymQyQXc+7FQ\nY4bijQC+fzNhEFnInaGujKMJtsCHi0Lk3EhAxtqJJzUHh2VLWiX3/y5ZJpzM\n43+vN0aJx/IXPbu4S1EwU2rJDdix+/PQNzpD56yLR+tH0+lz18vaQG65qcsS\ntQJ5\r\n=ZkJs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHFlGPvOmcw/7HpEo3BdRxGJaqk74iqEJSjLrjc9N0BeAiAcHOr4VkfHWLFiKt4zfVXvKFvxzJ1CHOPIMuKWQnJKqA=="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.4_1586592593929_0.9283504792819255"},"_hasShrinkwrap":false},"0.1.0-alpha.5":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.5","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.5","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.5","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-k2AmkmVZIErtzVPAe8BtFHevg5MRNxKEWQBHixlF+WKVpmMallri4DX8mBZRIGp4iaDaz9NqRZqeABiO80vrow==","shasum":"1ce367238c0e4dcc490c21aeab32fcffb52c0082","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.5.tgz","fileCount":5,"unpackedSize":484685,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJekuHUCRA9TVsSAnZWagAAaQ4P+QBZ4NtTdzMkyzPmZRY8\nDm9FYcK8MMCUCbbPCMlYn6KZ8+HrsfRhoOloxoMa70Z5BxdvLGgCKTLw8ELz\niTcOA8vkch/JLBFsAe8uIX8Q8htZBFtiwdtWrscyAg/J2X8grrbUrE6wIFop\nej3yrCb1AX0R8WFskSmyctLmwGTPFKrQGLxTMvATT972XVkZAkFkL7YmL/hS\nfX6EnacBjvZoUmEewoN0FaPYPV+UWX+En/e2+YTbuNUNkHJ9IOAEcrmCJTD+\nbOqQ8dhf7OSQVWTwb7cYyVn37iH/kS8Hr3ILxQbGJndlb603mKGVPaOpqbvc\nAbhuunEGDYbhMrJnMcqkoOxRM42LJpLs7o/kpaRxhyVxZyW+ZHzuc416Egaa\nWPgwY+hq73tzRfiwq+BAd6JvMWBP/c16IrQio7qG4WXJQl4A2uGtryXBEeHW\nM5JeTH4IjaJv6InLiu1nbndqZtX9kO5fpOOi2hP/idkCmls3TzwyjNJ/IXZw\na4iMmSNhtV2ScQJ7gKJoyOjyd56841oneGhReEGFkR56aAWwnm3S6lHjmwy3\n8gDyFNXXq4By3S3SBFpBQWSsjLd9xxBo9QYp8kXt2Yke6X7KvjigNP0a0ga6\nMbuDTDnK+quRoyS+NMA8bLCEmQZ3DnUxecYpxmUtS8ZeSfw5SvRK/5l+ZIBl\ngIlO\r\n=I+Aj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICVWldoaIQ9RhQ5gCWqOtmUAu4jMEnui1FII5ht1pRGPAiEA/UBLA9XiZaH2a6WDNoo+zQisGFFJFhrIyIoNmG0y2N8="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.5_1586684371601_0.6071736067586293"},"_hasShrinkwrap":false},"0.1.0-alpha.7":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.7","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.7","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.7","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-v8oZf6JgzmyhairD+yACsNA1nrBbLPj9E7U9MqzpzV34xqiFgRhHvplYuf4RhqGMBA+QVYT0Z/Pze7xBa8K4nA==","shasum":"2dc1236a376d047560846bdc91bfbfa691806fc1","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.7.tgz","fileCount":5,"unpackedSize":5767110,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJemI0UCRA9TVsSAnZWagAAHp8P/jZuqgQ8WY0GdRixCWP1\nfZffirSaItzc3IFZHQkZCH4DRMBnUpIK9WzQ396CJ3Dm833GNqr3OHX4xG8j\nhxYSA4H2vvpmk+x0ZIAC4bzRIpnusOqP3jNRaLuLWuihwhcmQneFHQDaKkIY\nlnfZT0MV6DKdaAh022mnVXObSXkui0//57koNPlPYvGt64IoIon9EEuSUPDv\n4lfkye//3Mckj7nyrrc8xQlDzepTKK+JPrz+0HZeG8KoAZIZJLrfMXkav2Pm\nwj5YH13N8fq6P82MkK8CM8KRf4u2/QCMEAlwEzFsytIs7ng/5b9CmVBOJHCY\nJO/HFrNZlseSVBdiNpIR8R22qf5SsV6CEkw0rQhFE17c44ZkbglB59bran5r\nYpILd7erpOAt50szoKCNqlH3xHIf597GSZdoBqtjMmcScz1Z4SgpS/9wYEU+\nQNoP+DTgXblPt8fltKSyUlsdG43l4EIyflictcHuGlZjSaSd83cIrSQQGPZJ\nJEUZo9Yx+nGO04rlBMpuPSbSO3H9+D9X2F/IhThQ1VDDZN+PGLIyMyb4vfBk\n1oYGe9JHfiV91w9ND1MPdtjS0WkFqffNC+Es5AAKVgwEp77XZYHh3uSF6tWl\nYSvUmEQFCpTORbqqzoEBoJbXJZlBQEf95IS4fny0myFTKNv60yOS1A65LEDk\nCkzb\r\n=kMyK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDQr/cRijyGM9B/DYaxoBd2XmnrbQ6Xf0q/nzokObmu7gIhAKLpxOs92//CwIYW0tiNVWOyz4GOFMt9u550jCfD+zJC"}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.7_1587055891687_0.9594522025312922"},"_hasShrinkwrap":false},"0.1.0-alpha.8":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.8","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.8","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.8","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-URRecyzjF6+oqIwX+AF0bDtoH4vrc9B/Vas05+IdzpBhgXMdauIcEvbk0Dc15vcS8iy8h/uYZFdGrd22Uve8HQ==","shasum":"54c5f8e72af1a3c1aea3f545cfaf553791bfcf73","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.8.tgz","fileCount":5,"unpackedSize":5773569,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJenE7tCRA9TVsSAnZWagAAPdkP/j4kmmL6M6+gc4rMdnvS\nPMbRr7QU3docMK97/HwCMJ2geIddRpeuahobzSnwJtsxbrJPs8I7Na5k732G\n1sh23dccRqfAVw0S62/kv+4Q7yxMDy0r7VJCTNztlxzQDoorurxuXV7xoycx\nWIK+poKQTMqpp/aJmvi4UlJ6RAjcBQMgw9W5szy1fXg6hOnbaR/lZWRuPCbA\nZIQuXEPKdlMwzxj1/XRuvAmQSMvy7T6fP3FcTGU1nMHKhEyFXQxXo3dYJLY0\n2o3eGk36UbQBYl4nUfiwsB7br/seQC3oSrr8DnGaoYSo3TZCNKOZvgWmbi/i\nLZsVsI8DV7nk/Zv2QGujcywXQK4pIWkyi8+cK+zcERx8xIJwwF3qyM4JysRq\nvtrfL+qtYhEc1/ezrk7CbwtV2EasPlpJMzQercWUkctqUfDGpupDtJc0zEQB\n/2kyVkOoCAN4Py58E/OaIF5DWxzmY52+AMBx3E0gEPN5zqD6dORPJE4GmT4b\nCbpB0RMYt1zHpq3dxzNVrlP5e8qaqaQpRhNUXRJU7mCvABHhMGlrNKsRb3Bf\nTet+BZDK0VVVKPk4v0q4JsHyCOkWkvia9FMIIGRR+dcHyfzEPxCortLkGSIx\nfPfwGMzgdklt49oSMdvrwrhcY5JzvdWLmDjCu57i/ZTAKJPSTA7ohJ2gQLCb\nkuBB\r\n=0oDl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICyro9Nyog2ms4iFQ1GSbYHIU1mfPa/+QIQj6iTyXNcDAiEAwzGqub+/GOgwzhAaLCBLzmWtq+xHq2s2cHDcSS1lCOc="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.8_1587302124575_0.5053862223555499"},"_hasShrinkwrap":false},"0.1.0-alpha.9":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.9","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.9","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.9","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-o5IE/Uzc7BxwUJ6MK/SHNjh5w7Gtg51HMWw+tkJ8noA6mkEQwKXnHRV4C8VKk0QxjX5SLfZ9I90gRec9n8+jYA==","shasum":"1f15d782762f1fb850f765c49312612e06681df0","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.9.tgz","fileCount":7,"unpackedSize":5779558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyPNwCRA9TVsSAnZWagAA8EcP/0w42TzSc/sfdlr0BuI4\naziK5ERrnnkbw1u3Lkw7wk6RaS5b6vc7mIaA4I0ubwneoCsXzitcsCnUJPK6\nLKUV1+PFPEhJeu1F8u9BzXaceu5V8dDF9y4caT5Se4t2wRLCLKuH0SzTb3Wh\nyBgm4jQ2u6OV4aprDoqzKxJt+2p2Ml3CKYvDpuaPSKBKfsveGaitYMHPLd7j\nmOYCmgc6IkVLFBbRB24SC6R4zysTH01PjIYdL1udb+R15px8EIg1tMBgkRAk\n4gZ45Mpe5RwMfU4t4hn60yba76awZeX9escqbqHPEpMn2OOb8ej8UUFtNMmt\nM6Bz+dzb+IABbWzmwKvjs1dQHm7S3qMZz2jpwQmT+MtAr5cAmxrGR7IJWtDA\n8RL8yywx3/Rs8Anv0jIjnucsPKmSuTMkHcIMjvykbkzL2da46el4dpbgGhSR\nh++iOWBfNtCLVw7Nalrz08F+JkQNuSZ+WdmD0A5zNNrtUlRCMondQKsr9qs5\nXZNjlF+bRoM3XoE7eG0Z9E6h9NC9DCuyvd8Stw+T4syREII++XqUCcpvvk92\nEUyefFxzOpkIMtas3+EDGAYBM1+tX960V+d5QpNKnDp7iBPqXpXdepSZaxZE\nEACdY9mLkDtN1nhdorxEE8U3955wC2fTfltTpCvTomVtG8DwfIB7gRTckN22\no/lM\r\n=bJgV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDWZ6rs5+kyZAOAYMrjL7WSeG5yCstZfCpzLwFp4zUPoAIhAP6zbKAwoBpEl/zHOhCKIu9mZZIqjfh+E/cRxu2CpuhE"}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.9_1590227824294_0.5606610717674791"},"_hasShrinkwrap":false},"0.1.0-alpha.10":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.10","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.10","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.10","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-4SNao4S36jeWPxM5/1vWhS+8w1PRk3Y5xsX8v0I+EEnvE3k4HMVi66p6oNGqvuG+c1wDGSHfnZFSXQatPpn22A==","shasum":"cb26819f920bd0645ead79f6b531bd8fb86d3938","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.10.tgz","fileCount":7,"unpackedSize":5779560,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyPhRCRA9TVsSAnZWagAA8IgP/i2BlF+Uwqlw2o6tvPap\nFXZRDTyCB228KzRSBRGEVLw+675Uzri57ynjuZuyI931YAsTXDEJLFtrCI+6\nm6Q/kKxHDcBKcooGPqJWsebPlJ1n5K1D+8hRxxFeaS+Pw/fIc/Rja2Lprpsc\nubKkLN78eYa5bQDcIs3Dujy4kEagUULblHf01dV6hUvXeRJv0g37t7qAfqsf\npwnuSIsEM3EZCo6isGTBZf7yBaUHfNe/OVukMyjHwg7lXADf26qZypUhGQHU\n88BPd04MYehE0HIsIuVdzEQgcH+pB/wkhFmGMUmXxk3ry4UcCuZPmJcjYx0J\n9GXYJBnLxcu6uxpPjqh7LP4ml74c8NiaymB20vgXMYMiI7jBDASjcchg6AEO\ncsutjo2G8JdQxfUC93Z/QkZoJE+7jfcTi4rp/1PO2NcIctXjB2RvNLT3waJn\nhw/0aaNUB2cxN2f0XJFj5zGm+2EIiRUpGJyHelrozqYfBmyB+VBvD9kcXN06\nBuoDqRq40mybsh/Sfxj6T59ALJMOUz1HfyPIlU+aVyxvsOZl48ibb2gwMzpv\nnV2w5fOeP1YauQf66rC17g+jve+9VwaEYn/CHgh+1kxD5PM25V5+zMC/olk2\nrZsTGOmqjjHkqjvbI6TLEbSAMCyfSnVx6diafuHk5Z9G2+jxXvK/2W+Fae6C\nAiS/\r\n=+LyD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDPncw3jwDLEokNVAmr16PpOz/l9JK92gEyFA3nYMQpuAiBzJtPJsBoJukFdS1SeYhi90/yOtGtxp3yUAp1OrJWBFQ=="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.10_1590229073045_0.222417963206629"},"_hasShrinkwrap":false},"0.1.0-alpha.11":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.11","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.11","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.11","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-Zjq6z0QjBjVm3706OfoI1g/RsiNjSp13kERsOHpcaqDWJ5pDeBm6txHweWkpSUoX3QVeLlVdELHRmnjfXjbrog==","shasum":"4ba45ac170c8e56434466659b35c2d994cc4e385","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.11.tgz","fileCount":7,"unpackedSize":5782234,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyQgnCRA9TVsSAnZWagAAkRsQAIohbtySEFvtvycUbtwU\nDOFfjvzrJqCE8slJdtczn9HLVQdBf58mDowgWGIWYmPqgrQoOiDPydCgXQSX\nt8hkSRitbjr/wW1bNJSPs/0dushNHSyxM+AoCERgPRfns9zbW7ukFlhM0FNf\n01ZlAq8XTWcmn15/E4UVQiDhC4Cy5+Tc/h+acBqNWcrBoAHTJdapSUmdo0D2\ng6NWGM6pKFtkcfSjFK2sUIstJPxBkCFnQI23pCjsgA8GqzmjJv5vg1Y9gw9g\nhmMbcwX7PvfMdc7rwaFCvKmlDTmldNhvDZG6ZmWKU7TOm/XFEbDvpZej23WV\nyg7fI8BAFIJH/oHbfeNJ3PMwT/9ldby+SoX8ZFBfIzQS8UmYn9X2ssct4i4+\ntVd+XsMWolx81kIhp/oTcPNcCuYktLI2C1IyYmbnZu5CvGJzRYh14ri7T8mB\nz5GSKfCvKtzBhDIovoYw2hccuTCVDWYM1GtHRwCt3CECGwW/5qqS6RYmh2Ux\nMXaBlRLDM8YfgRQv4mS9aeKxMCsEhRKbAyFDp5qRzoGhQBmaJqI7ion3RIko\nmCaLNPq5G43wJRJoe6ku748hUY2fZpZA8/JV/UnzVSi7hCsIDENZ5izZ8qxs\nhRnIllW8jBb6FegyF8qyqv035s4n9Vp5urEOZx9VAUrHz1/S3cK+0jbEywDc\nsNX/\r\n=myqt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAe4iYKnHg0f6Pr+5/p0B/0w3WtuNSgaiLY95obcgnvkAiBiPOwsqNYeT0yQoanFEXySie7Asqm1xOX/S3/tMNghbA=="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.11_1590233127324_0.8188324927622266"},"_hasShrinkwrap":false},"0.1.0-alpha.12":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.12","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","devDependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.12","typescript":"^3.8.3","vscode-uri":"^2.1.1"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.12","_nodeVersion":"12.14.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-JVmXVaftzXWAHZViowg+MmtQDXKD6Hge82TsgMHt8/EE7j3Y7LaX0dikjTOAhTXpXT+xOX27QqIKo6I0x4kjPw==","shasum":"b2c4fcd1d8d48205ace7a8e9d662a48f9662ed20","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.12.tgz","fileCount":7,"unpackedSize":4543960,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyTz3CRA9TVsSAnZWagAAZHMQAIlQb3IUwOQm8c3J4ifu\n1Hnr0OQDVxNYWUgxsJ9UtlB1wNiBTPvcioOMFFdzfNoBfOXmPl3aAOHtSgsa\neoynrlSkPp9iDsB8ER/vu5CTGhHKvTRFjJcVyFQqAGB7mP7CFfSGyaRmthsr\nV/L4SoC0NVXFsnXBoIMLVvARu1Npo+E5agYqFEIMOJF6Drvar4E1SefkHvPu\n+ePcGiwj7vXUW8ikZUU2X9Yo4rJ0NQl/Oztwp+q6OKTOHkbSLtn7SKd/Q2wt\njvsEHBmNphVld34lnrq1aCmJORTISOyqL5YFJwYtC5/P2zaF+nJQm9zPwJ+0\n+Bt1KpTlGBldERpAAo0yv1gzFJqlzfaudLBj3celNrjFfcdY5OCl9R7zzV3k\n+YSeNJBVwhfbiFPvfmHalUKsMfzlkOKAQwJLPbL0JC5skT3SnxhCdFsQvXog\ngf73nZnfigTbrAkqUhe+NiNUvqRQQzt1hjYer/nebSk1NgpQ5NQtX1Jz6LgE\ner1aIRBVnKiB+qxqMykhT+ybdBnpmOqGkqTByMN4VvuUCmdWNssOwjcgREXZ\nJ8WxkA1AiMdAx6kuOPBjwutZG0FgrjzZOKnNoQBk1lDbtqIKgLqtHDp7H4+m\nDGUyfoemJV9PWEE7WBYLL4G7yrmbnYcRt1wITpHsvJvUjpqD1OSvkwme56qU\nSiUS\r\n=1XtE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCawiwclgfYm0NF3GFe8LPvbTLhH87gO4+t2pW3siMsRgIgHNG7iFGQm752AJ0yoD4SyxjRka3QQyUTNQ4R/QvEYd8="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.12_1590246647024_0.7405296248717284"},"_hasShrinkwrap":false},"0.1.0-alpha.13":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.0-alpha.13","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/vue-virtual-textdocument":"0.1.0-alpha.13","vscode-uri":"^2.1.1"},"devDependencies":{"typescript":"^3.9.6"},"_id":"@vuedx/typescript-plugin-vue@0.1.0-alpha.13","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-vZRwoMbkJze2G8C1orQsk/Q7pgfnX6JnPqzKJjQkzQmUpEpYLM8KBXkZ1XKPLXed300FfdjmDCH8VodqOY49Nw==","shasum":"b6be4719fb5bea2cd23fdf0f2855d42f8bb4c33d","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.0-alpha.13.tgz","fileCount":26,"unpackedSize":172175,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBXNgCRA9TVsSAnZWagAA8HoP/1ffoJxqsOVJdVI1vdHf\nhMajNUw1NwMb91R3skQaLkQ0qijWTjgBZAxgv/PuuHZmUpz5fFNHgBFu9ZXU\nxO5xQw31F+Wt8pxUNm9rQQDZ1aue3dqvCR6tx2z9jz8W8XrbqafvhxFFNqjd\nZpQVR6n6NnNbCfzl5LHp9b0aG7Apb5tyzyM1dw5yY/KQ4H/biQLjn7k6AfEA\ni5O8BxgHWUqTt8N+Lx05qhw0lBQpqJEnFIbQGEvbfb1ppQHOpDX3kbR5KSXK\nvXDjuSkVKV/Z7y9EEMb0B9G7kC1qbLWjzFWrTEctohcO8adY5SEf8hurEx8P\n1TL82hDppxDPRNv7ErgbqvNzYmJT1XUEf4t1/hPTvyK1kM/gpO8/V1iEvoca\neuCSzYjz/fEODCw/BU8eh5M5DniU11Nt0i08fMC+LG7EcGBXpZoupZp3nD2A\nSAouOHdiUHSm2F+PU+RJszQAGLPecmLJMBtPBt/juzhgsKFS12vUUdSFI6PF\nqU45BTXywjdOfjqh6Gj2Zz6kn8S2Q53POU1dvZquuTAWXXobEBcQiA5YWxuF\n77DeLIhEjPhNz4XUYYDO+wwiCXwLScG0CA7RHLOyr/jESwwOj0igjTlgtXDS\nyLId2ud12b5gcGvCYqu44T8Vx7yRd9GuXNxClgVxUFFDMQAYWtRESi3Lg/B6\nfcCV\r\n=Ivv5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBlCL7nZxhPb6+Ds0RvdzLvIIV3VIqrYpJaqdilTRfM9AiB1tuxgxQ7dTrxRuuVMt94AmS+EVlUd13gKFMyhJYfl1g=="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.0-alpha.13_1594192735591_0.4214073190933041"},"_hasShrinkwrap":false},"0.1.1":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.1","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/vue-virtual-textdocument":"0.1.1","vscode-uri":"^2.1.2","typescript":"^3.9.7"},"build":{"external":["consolidate"]},"_id":"@vuedx/typescript-plugin-vue@0.1.1","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-bZQx8acg2LVXUKLUDIequsTP4FQKvbsCWUejhJ+Gi03ese8qVvAE4VvAlG0ahdhJFzjby10x54TgYxgzX8ZiVQ==","shasum":"99fd95b1c1952cc754b9a9deaecbd83f3adf8213","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.1.tgz","fileCount":7,"unpackedSize":107468,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJ8ObCRA9TVsSAnZWagAA1OQQAJBiH1/qbH5wKeZGsY8f\npbqz7iCOha0mxM+gQEJGdRB3kKww1PG7QlmvQU4SP+ENAH5lQqq6AyT4EqsX\nsoZnKvlBeyzQmrBhBkRJrT1Wd2J9cUdBbewmtW42fXgl5ZcjFgDuBKWL9uTc\n8hMmWOnGkPEmN4pZv2+Aa1k20D0FcZJmOdexDRpunI3jIHaSh504CqiL+J+O\nX2tmazst3l7jFIVe3gHhg0NlFjQI4KTrZC1nfY2KMQ41V4DdJUiIaxeuCn8R\nBLrSv2Em9X+asCOhGrKlB4R42iWD1eHUDQi4ueghqBIRXDM/xLFXDyVwqd9w\nDfk8W58lQ7ptHd6nrBksn8GvCmIaFuQAZ1gRkq0bThcyyAg4DbwizS0JWZuq\nhuSuluevzCekVcpqr6LJPi/ahMYxXIxXJV/trDsRC5Hm5ahvce+B8BepOm5Q\nz+8lokyqp96zcwA9d+GZUh7uOJoJIzljYHQbchCbI0TbZthGBL5BqYXQCcdG\nMxW03xMY19slutAw5RBlBcXZmRBoP+3hVJSqNK6IKM6fVz/BRdw2wu83di99\nJcnUpARMdeDlycBwiJA8JniWT8xwtKJIohY8KVsXzvICv4W+Lipg2SkM11k7\ng3WSnp2bewCyW7SJM96n5iJswDkqPESnTnEU75v89jC0x/PYRJEE27QLSI8O\nwxoN\r\n=D82/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHd1vW9XYiT+gCw8kpDqadJrJMmmz9aL+YH9QWXlA4V9AiEAjyxEzbAkT/ptma/2gCuV+WroXh0rMN6+gyfFVIAfJa4="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.1_1596441499449_0.5173204511598235"},"_hasShrinkwrap":false},"0.1.2":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.2","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/vue-virtual-textdocument":"0.1.2","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"_id":"@vuedx/typescript-plugin-vue@0.1.2","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-YbMzfH9KxaqgBHUKmGqpojgEvU88E744N4KsUV2ZYBD0yIMlrt0f7BeP2qNNdMlMkb1xJcsZMJ+mr9p2LQOAsQ==","shasum":"a94515a1e4fac17dcfbd067a1c55731a9a725ecc","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.2.tgz","fileCount":7,"unpackedSize":140840,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJ+9nCRA9TVsSAnZWagAAt6MP/0qPBbA0uU+p3n/p0BUq\nNjnpqHKlsMV9tDP2VnQP0nPdIsk+Y5rygf83oYxZ88vvRsfa7np5G9/KxdPg\nw6+mLmwUXR8Dp2Y5hxStP1fJCM9PqjuPR6oKbGd7WLeX4e0jv7tS9TxEQcIG\naqXGBQP31VOfRXNKtMGQ+xwjWKYdpqKQkIf4uqR3TUxZ5bgbU2JpZb8yn4JB\nOqh9pYBXbNOAEMpSttqC/HpxVv4yB2mgy9Ef0xWUNgFFzlIy/zbCpx7Jvlfp\nE2PUC+oglMwKXlpvWfr5pVbGr5zLaKkKLv9kwweYkGh9b/76DNNy7z6nWTyn\n1F0YA0Z+Z9qzbxjOIODmNkZyoXoTDp9G1MJI0DLh8W1O1Rkj4SoFJziJmkrw\nZk87HhbOae6vTE7eAAicvrxLpj2DcYwE+Z2uOtR5L7C04gjF/+xs4PJerVvh\nQXHyiFPtOH3sZ0Ipvw2EohATW1Aw9Io4CPdEmg8fvCN/GiTCwDm8+9Y9UQFq\n0mHroHvx6VMIxSv6B9eGDE3ZIYNs7JcQ7z2iCox7BnM/LXs2NJm3l6vGzX05\n3xYxdl0XoaAVR6WlQENg2AoMGmF8ThnXyuAs2xF5zHwO7JN0aDMciQNp37ov\n4XocEVX+hBJo5/y0N/6SU2Ix/4xH8L4BWugjqSiqj0KDF0lZERlyn9W8ECt2\nf4oD\r\n=NKlP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCuotUykL39MUnaJ7nUkI3GzHUZWfxQCgpA07wSlDK4MgIgISkFVkWyJ+55tv39Z8Zcyx1qOPS1fBcez9x/uxrh5+0="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.2_1596452711504_0.5529505062252411"},"_hasShrinkwrap":false},"0.1.3":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.3","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/vue-virtual-textdocument":"0.1.3","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"_id":"@vuedx/typescript-plugin-vue@0.1.3","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-EP7gvbFmTaGbGmMCBkSUlAQo08nkzSiUi6QrzTYvQQnM9rn7cuaIt5fNaDlVYGH1yCi/qSF4ajL/fUGgraYZug==","shasum":"2967efa94a40ea3947baf193f4aecdf4087fb253","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.3.tgz","fileCount":7,"unpackedSize":140840,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJ+++CRA9TVsSAnZWagAAhvsQAJ9FlcF3tNqcpE+B+pTz\nrLFCTgatXldpTlWtBJ2s+6AdxR+c/I1ZroL2CLL0ziBzVdntCikwUTkNRV4S\nxy+E7zdoOYV6T7jUS85UExH960HfKwdajmG8/9whOM9o0hqwkq+gEhTBpueX\nqPzfp8jCOLaJYmR0fPNScUBNO4/niUCOLDAtrO0RGLsSRz+XmqqEYTz4lkYH\n1i1I88Uw0HbeDzZDQBUsEvAbSGtICjI9rDxhuGJS8v7hNOzOsCCKK6rGm0vf\ndfl+bmS298nfzqLMLCo5py9gGJk9S/pJj5pywstBSw+NDw3BAYudKrbUl1R4\n7VkLwWe4CsFptN45ykq71yck1JUdCX9gXY1ZAMXRZKyCgpylujr5Jl9/OT3A\nFMP3A/pp7SHOARnkmRXPCKHLxUPMrKbFlN/YcB+tZFkIyt06H3CQBRe4JrSy\nd49lsCdttRipzFp4Q0pwhe9VK6Dxay+IwMYs7EEr5VaE5j3OrRFWYW6TJR3U\nfT9uEyhsIoqH+/xG7uxfIpMm67epCfFWA1YnicpGCEafqMIk4wqPYG66JWNs\nHUk4Wnbe4y8WLSyDLilrqzj+fUwmQeoQ/4M/xK0OiG9d9R4StgIHFMfM9UDZ\nEAFRjfNEj5uWltdgvPwPyR/ctBvlP+Iwb9aU0NJzTmLKx1MPIByjb1RsUNVD\n2dkH\r\n=6yD8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDGeR4qG3PzyzZQV7pEGt1xMfLteAKt7u+b7nH2f4zwTAiEAibBo8AKj0Zz+qNiqJNLwf+yAoJ+W+dTnhgEy9ck7AlM="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.3_1596452797665_0.7594599839578438"},"_hasShrinkwrap":false},"0.1.4":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.4","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/vue-virtual-textdocument":"0.1.4","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"_id":"@vuedx/typescript-plugin-vue@0.1.4","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-mvhXK4lBeHC9/befgWAiRMwamagH7NGGFPukD7M3RPKEjPc9/J3k8cIsh1lPg5YwnsaOUfeMch7shRdzGhBoyg==","shasum":"05bab9ddaa8c2f730760744a871324e7b96920f3","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.4.tgz","fileCount":7,"unpackedSize":139604,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKA+qCRA9TVsSAnZWagAAdhIQAJzcXpNSRSRv9nu62FHJ\n+ZCKeVkjcfdgUJCPsPnLjoxsO0Mu2L3NV1uUKYdxNArgnpMLsaYie3pNc01m\n5WkXSoey68SZ+mFlPMXaNZh6zhfZ1w7Ibcslue5q8bTMI9NhDwdrmuPRSR4T\nimZ3pWSQe4tZy5eKAisB86UFCrTFNEjQT9WQuNCKyrzzzbNE3tqtr3Am1Ixn\nhaidGJ0mDDcutKFNzb3Yb5ZDBfZTxlTeRm2dMlxxJriIC2gPUC1Oz5PBpz/5\n21tqvY262lOXX2PndzZ/GdqjyZ60q5iRQ2IVs9F/+BYgsUz1QPRjPbbkhvOx\n1VwEHB4RdUQslZNB6qxDQNVCZFIUg2NNagehAeHA496OOmOxgOwU+lq9QT6G\nGT7+gt+ATmOFLrq8gCSidUsA6pDrEHeoqrCWMk5BxaMreDAtvDHGbyLdfNcI\nSHOjXEeAAJ1K+VplmWRYLGksJl97Au0qTq5V/TkwXNLbCTOOr7hs+dIrOCv9\n5vEXTirfqH/IXfU7jIafW8w31mAcxafOI97fVAaOrnFS2T42AuCKlHnmAK4A\nGfyoVstxrtA2mxPdm4L+hJoIbTIHBlMuKMZNV94tht/5Uz50JY+/uquQOvXC\nw0n9GNw4tMnPKiMK4eq4vVjYkjSi4tl9I+AS5VDRe4C/DzplZSdAn7L65ZJT\nb6b4\r\n=ecgk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDejaSGFGXeLdk6ZJScVbnj+tl96iPvwWStorbrkKF1zAIgX6LN5suAWwCaJuFnfcZ8mr3qgimDUeBnkTDgRqOwq7g="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.4_1596460969906_0.7499431094037197"},"_hasShrinkwrap":false},"0.1.5":{"name":"@vuedx/typescript-plugin-vue","version":"0.1.5","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vue/compiler-core":"^3.0.0-rc.5","@vuedx/analyze":"^0.1.4","@vuedx/template-ast-types":"0.1.5","@vuedx/vue-virtual-textdocument":"0.1.5","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"_id":"@vuedx/typescript-plugin-vue@0.1.5","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-OjvIqHAWiHmD2Sa+66tMfB3tZMdWL6N4HSzPH0D4DpKA7e0w4fDDg/CJfpPv+oeunqQPlbK3+vDUmoQm+O405g==","shasum":"5a97ac8e2a85cdc492c99e9a5e2503c00e267703","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.1.5.tgz","fileCount":7,"unpackedSize":166692,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKTHlCRA9TVsSAnZWagAAETUP/ifJqcwwI3i/gfrBDmYU\n2IPbad0ToEul5tLhz+v40w9O6txgFY08xfwjnlISaWVSL563xtFHNTTP4mJy\nmvuiiUuCQvDefUaerrI8wQxoy69JPq06/0DXNzpyGgqMJseR7snGcMsCJjce\nVJUj5RO068GBx5bVT7CGT5njpTcRQDosQ/3JD/TducjHG82uM3FLerU4EQkf\niYXlIvq5BcDsBTinVfH2CsyoMLgsGcc0fIdLX5yxYHlmL4Tliq6rHbcE+lrA\n6b8yOFuXnSWbpwMbbieirItsTqQG/A3F8gntbaISGX5lEtql/+7pNCk1OxfX\nUqT1HauFeJJhmHhmtqdqEqfCAIH/fsdui2GWzOxSKwPiRUMahIu31tCXbgMk\n0zAA1l66kX3yvnyIVO+WnYJubIfjUe0MUh4S3jzjnh4CEVy2XnFH5IL7F9ev\nldce8Qw0U4NKoRAmll5D6OJUETLgYJIFc//Rj7GCVqG+0IbLkdj92chdMjjx\nFqoEtPcpeSXfajzy+xHxt7GkgU3ypKRVKSrJ0ybdNypbxWSfihqTfkHd4xuS\ndMnxaotNJ09H/HTBi0AyDUaHa9t1zGKJJj6oPBEcjg4kcdoykiDXZMre87HN\n25TdQfmcobySHKO9tbhSrC73tRaJ36BKK9CIemrEhAA3aK2mRgyvWu9zYI/h\nATJt\r\n=VbjM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEW8bMGXBX1I9ulpYnj0p/wwmo9QkegqHl/eawjrOh6DAiB9Bjap/dpmtuRI/map0N7vmWrBow5mcldHxsly3eSnXg=="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.1.5_1596535268985_0.5363865241264603"},"_hasShrinkwrap":false},"0.2.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.2.0","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vue/compiler-core":"^3.0.0-rc.5","@vuedx/analyze":"^0.1.4","@vuedx/template-ast-types":"0.2.0","@vuedx/vue-virtual-textdocument":"0.2.0","de-indent":"^1.0.2","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"_id":"@vuedx/typescript-plugin-vue@0.2.0","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-OT35Gf6n+lAt4VsjcDfMq3jeaNET26e5NS7NSvjDoZnvZUG493cbzLktNkeagNZ74K4fu5WH/LDdGbcwBTpnTg==","shasum":"ccbb5f4c227522660a4d546d857cc0ea7028ddcb","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.2.0.tgz","fileCount":7,"unpackedSize":234255,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLpo6CRA9TVsSAnZWagAAwLMP/1ldseeNwZ/pO91FPHhY\nshjJfb3sesdBYQTMI9UVIAkz+V1s/8OkBuBm5oLWRvgz/U1d4QGZU40U+LEL\neFgqs31wEXe0BzqzLoqD/BEu8ooNGNpnLz2B1pXzIKINblCTf+0rWNDNBune\ndVRFazc5lsLkp79IiJ5fvUPGMwxSoialj6HajUkX0Os/fqY1b/VP3FTkh8H9\n4Q6b3PhsMX5BAVEwH6UWIHzGfw7f0zCSfAty2xFLy/MQ9bcdAQ4SdCisOWjv\nYl2/HPkH1bdzwls8swDsD1YE/kRFUWWVu3hL4VFJMrXihkkgEJhyiceY4nMe\nZacb0x6XZWIfvA/24QDCyPchLxlcl4yRvN9zvDpJb8mCuTRKSJdMVHLeZwN+\nSQDcKc+55HzOX4ICQs2NrldFrFVAUHV5lki7j7tsU5NpLJBZ5EopwbQ+W2Rz\nN9Lw2uR3KzXVTgFvBrPBkBYB48CbE9XfrBe/2mbzXudyXaVrg2XAwLURkEu7\nL57XXrxDDU6qDCdJdS5eG9mB9QLAMTIJrpaTz/Ca/OAfgJ5Y/jUHngLxfzYG\nvSbVTFOmhqLrYHbSbbC1290niOXFkwWKmCTPiuwkduBvlCwGli4xuFS5upud\n2p6rXvQ7kzr4nEYA5Yy/2LoWstgoKkjD70pFTWvxx3G7fBZKu3uEcZ1EBzi8\nPi9k\r\n=GmIV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC88Zyd3l9hsfwsHX+aD06fvPIfvmLzF6Swul1/VSHdwgIgN8r6RLbGNmpmdnGF9HqC+LPvP6jjQsn9ulqduuvZuIE="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.2.0_1596889658401_0.6483522304668758"},"_hasShrinkwrap":false},"0.2.1":{"name":"@vuedx/typescript-plugin-vue","version":"0.2.1","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vue/compiler-core":"^3.0.0-rc.5","@vuedx/analyze":"0.2.1","@vuedx/template-ast-types":"0.2.1","@vuedx/vue-virtual-textdocument":"0.2.1","de-indent":"^1.0.2","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"_id":"@vuedx/typescript-plugin-vue@0.2.1","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-aOngxUaW0kFB0gmIf/sz8XyLXqoVxycmz6VmGpBf0k12BdVst74wwIHolPnkGpDTmv5dhx94sxzP3RLzaureUQ==","shasum":"49bc991e7adb5dfb937bc96cd9ab06d51ea3fea5","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.2.1.tgz","fileCount":7,"unpackedSize":237422,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLrwmCRA9TVsSAnZWagAAauIP/1kvPH6Hlvo1ABfvQncn\nuzyJ7ltUVr31hSdz3jLZLnycPq90HyjlfSPnJjPl7tZW9aOkal8cUWTKHqUI\n2p3+j9akcOwbCnyQVFXe/IjYwBMrCC3gjG1BNo28hCZ9xAEJHwWZ4ctL0USb\nEx7qQqSJwoi3D93rI7j9mc0ezxWa+oDiTK547UZ5hg4WIcIMRXcd1dr8NEFg\ncEO8AOVph1JOVTuLpKgrG1Dsw1Cfd2Bd7muqBlx8A3UNig4RM/kLkwmuDBu1\nYsbNkEQ++E6yf70ewKHHGtGySuPVeBzL+s5uPwWXBbEla1IUij/N3LADdYcE\nCf07t6Z2fjh+EsBHtQH24jm+FvZKbwwM8ZGMEZQ3m9GOS7X7lHut3vMzw3Fu\nMDHug8oQiH1+NiJ+YsNvi+7sNo4ep/pxUuqyCZlNPgcyE8yoh2vk4v4ZT7YK\nLWqU8EtAIvAYhnWIh2GB9MpEo3YxympW420giAPqcO2Ej71cBkHNtVIv2Gz5\nOfa+fTsDwYbmt8WvtaUN8sXiHRyT/E8pyfM+48O8BtmXyaTOptwXVvD6wPsW\n1VQfSzU8NYV41lDqB3u4rjghjXWvXelODuaDX5j2oLaYy/PQ/PmRvaCqrdOR\nJJFX+wC6MdA3NXxBC9h47Y23eD7tKfZxFOYh2X7s6HM4O9G4OzaNtNcN+39b\nnFZX\r\n=gHyz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC94YhIap/rc02OD5sh0akC+GDpI4QszY3fSmTz1AOesAIgWcTBSGPbpKxkfkuKttTo3Jy3vgEgMyvsIcI4VojD99M="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.2.1_1596898342389_0.24739516668228645"},"_hasShrinkwrap":false},"0.2.2":{"name":"@vuedx/typescript-plugin-vue","version":"0.2.2","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vue/compiler-core":"^3.0.0-rc.5","@vuedx/analyze":"0.2.2","@vuedx/template-ast-types":"0.2.2","@vuedx/vue-virtual-textdocument":"0.2.2","de-indent":"^1.0.2","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"devDependencies":{"vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.2.2","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-EBTQ5no5a3ypngyKut2ghaEhVbbHMGyvLOpQI7upTy+HnG2S7OAXnVMIbZNTtg1wLb8gdXX9uUnt3cRzZ+qMUg==","shasum":"a70d37d56fe90d4a257ef50be982caa48aa180a8","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.2.2.tgz","fileCount":7,"unpackedSize":254499,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfL1H5CRA9TVsSAnZWagAAAmIP/0crg2q3ieYn1Kk4Oie2\nJgt1kQx0XyyWIDeLlNkMMj+L3X2jgfgjv1rGhMJpVaUw8WXNlI6PWl9OgzYm\nQN3raCt1HG/gvNoEeUcPd4EFzl2KauC3RejggS9k1CKGxpDAZz+ld8tQEcGy\nrRgmyYo8w672vMtGCfweGY8UJUqHlqw67bz10x7zGa07m2VbrayFxc6JVrxY\naTcl7YNgZTx0HCF+kPy3S9IpfqsXQCtqkgJdwMu3HXODAUsrCRSlSfDXNt8+\n5DBKvF2oV01l6QNCEjJIafx7z/h3mjzgHS29OZ4Cc1jRVh7uMqfmrIFd0plc\nBCT74UpXA+SDiQt43n8kkGLfKagATL4IQOSl21E/jgMh9Xq43W+6g5LtwbGm\nzF9xdMNY1txVzGUFIof+KDNZk+Ih+qWy2pVKkjBaXiaC5aY4xdXGLtgmyE7g\nt0xHsaFbPG6ibYVB+o02ywvL7tZc/zH6PQyl8x9W88Cqxxn0vrEjZoNk7Phg\nX3M3KEN6MhLJ2HmQ3fxJecB7n2qKt+lTyZOySFPyPKLvYrrVoI/uVl3v77R2\nEzGK5GwKX5/PId8JrEiuqQltgKbjUEWMqJAFN5a8hZnTQ8vsw/jBK+mc72NE\nxRfDdYh74Soz/mTGiwQV8ToLohrWO5JLlQeNe7+0xehPx4qVNDUaOct1nexu\njAWT\r\n=qRTM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDwPd1lgJerKaxPwmELeKYMJ+LeH0gbUUvXd/v+tzHHAwIge87nuJtDiIhDFKtiZcYpmrX3i5xrReS3qOcYnGHMQ7g="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.2.2_1596936697173_0.47984254661914716"},"_hasShrinkwrap":false},"0.2.3":{"name":"@vuedx/typescript-plugin-vue","version":"0.2.3","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vue/compiler-core":"^3.0.0-rc.5","@vuedx/analyze":"0.2.3","@vuedx/template-ast-types":"0.2.3","@vuedx/vue-virtual-textdocument":"0.2.3","de-indent":"^1.0.2","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"devDependencies":{"vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.2.3","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-3P6DPnPv1JkGqUlOi/as9btiASJvPNyMT8WNRMZpAZI9eb7fj97c34N8oeLtNyI700CrnCiJvWUKZmJpRofAlQ==","shasum":"b9ab41a8af29a4ddbc44e90ef41727f048879218","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.2.3.tgz","fileCount":7,"unpackedSize":250090,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfL1beCRA9TVsSAnZWagAAp24P/jIPXRlRJrEEXDftVIqg\nFQI5WydbISCpASDdft5Tdqkp8rpxspKxiXwMggRYU5b8c5TJeg6fJGX2hYw3\n0VL2GPV8/4bwG0kRdD6aquZO51MRW3wJHYyWYgQsyV5ZPEjx6qkotLu2p8xf\nru7cX7fvU4DZHNpE2Hr/ixk/uQNFf73h7w9lLqbD1cQtTfs1dPkJ1/WhF2VI\nHzjrISXbm3xl4bd03QrGdEMSQ4gasCW42hslB9wfoEFFKCgou9T3SumE46Hx\n0Qs1a1XNHQOJbx3Rn93yyN+XtgtzkOfEYVlbN7ttYyaWQ4WHuqQtBaLK5342\nHeVuX2/CgMFp8KG1GxHjMeHDS5m3jlDUlponiOWxCCoiHQCf/rdyOcuRzHFP\njmaV3WPKSx5210tJvlQcsmeAdmWT8Im18uAq3bfKFdJTIoWP99dyde6MM0bB\n87JDTEdehCtF1eT4T0G23brkiKtIMlc9ujdeGaS1JMTFVHRD6MC933n3JQ01\nAbVgFgLlTqafpUXOfWmxcZUs2i4x1vXjV5T2Tord2R6iK2WEbY22Aeo09HVf\nJ+QtswsSKX95wahOqFpHZOJesm9wQ2WCASNw5kgEU4u6iBlPhb/sSAXZjOla\n56WIKv0qFPd3iF/JwUIOoZDOGN7FR4Y9cRewAuMEgFkB4QXN01DyLSm6zSFj\nVQ1W\r\n=8H6d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCZzB1p41g+C/1vmVBtF9Dm6PDWPAk+GgduQP1bw5Q0pAIhAPjc5Fy4FKGb5W0wawcQLH3DOmXKKUHZoCi89/pCmeTE"}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.2.3_1596937949657_0.5553795188065949"},"_hasShrinkwrap":false},"0.2.4-0":{"name":"@vuedx/typescript-plugin-vue","version":"0.2.4-0","description":"TypeScript plugin for Vue","main":"dist/typescript-plugin-vue.js","types":"dist/typescript-plugin-vue.d.ts","private":false,"scripts":{},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vue/compiler-core":"^3.0.0-rc.5","@vuedx/analyze":"0.2.4-0","@vuedx/template-ast-types":"0.2.4-0","@vuedx/vue-virtual-textdocument":"0.2.4-0","de-indent":"^1.0.2","quick-lru":"^5.1.1","typescript":"^3.9.7","vscode-uri":"^2.1.2"},"build":{"external":["consolidate"]},"devDependencies":{"vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.2.4-0","_nodeVersion":"14.10.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-BB5S29B2JRmmaglM8gJD/VT0Ika9RUnZYUCOMCopHCItyTbFC7RLJkIZg9rZS77R87/alD5W316WxqgE8C9XYA==","shasum":"e07485139e28de823e5153d96a2f71e82d0f75f2","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.2.4-0.tgz","fileCount":7,"unpackedSize":248154,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYXHJCRA9TVsSAnZWagAAuZAP/0oxqsaAj0yj8hFZrdOk\nUB4td7DuuXlf0XtUKy2e/MX5oi7vs1USRP6RhCcDUkWtzg+9NtybBKAmkF9H\nJSNkiVsSA+5Bni5BJIRIqY4x+ek5LZ8hxLxB3Yg5TZlw0hlgZ011xlQIjTk9\nHOgoR77DPcMVoEoTLVUaptcgf1LnUsHGjrx0U9aOOD7v2v40LOYb/rHahcjW\n+bnTCoR9C0H85u5lsbXJsCMAHnHaewgr3ONm6Vy7CfZcybbEpRMgqBGR39Vo\nF2T3NDmuv7E8zOacdoRqUvz4bh/3zuGzQepP3Cv5q10NEGO5qwZSaT/QhlOF\nyjYXI+/rjeJpIiHtGpKhijKf9rjbZhjL3MsEcE0HloJn8VhK60UjLNVzKDIl\ngikCYJCWdPoeQeUUltv7LLw43JWSpHywMa5IcECFBED7OaIoDXZrHEhLTnbj\nQo7Xn7godL/tfYw3JX9VjBFL7PQg0gXzhgI5Sk3rpYnFcSrPRqYqswdJZ9y4\nEInoHMtI25jHebJ75lSlenEYE3jHict+9XkPFwpX65QQ9sE+CYtf9z104dy5\nYYb6Us8A+CDkTM9VfqpmzW+waskkGc1opNOP8GntQGFozEmtQiEUYMqcT1az\nfxyNGIySlNZ32UzCrDnQi6seq3KFeJkhOghk6hqPSkmaagHwESn2BuQ3GIYe\nzTlo\r\n=rILX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQChtOGx8wAG5r8hOFs3MRr7rGl8cxcIcahNXu8Xu2KsRAIgZyb0w9SfxXUYdG5Fiu6NODF/e7n82CqcvaAuUiHB9ok="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.2.4-0_1600221641481_0.882558646815145"},"_hasShrinkwrap":false},"0.3.1-insiders-1604106530.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1604106530.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"scripts":{"build":"ncc build ./dist/index.cjs.js -o . && mv index.js standalone.js"},"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1604106530.0","@vuedx/template-ast-types":"0.3.1-insiders-1604106530.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1604106530.0","de-indent":"^1.0.2","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1604106530.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1604106530.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-yoFV5BQaRTOM/BDnaZE32rQiyiRYvA/P/JSNIV6HirEVgP0o0+N0uRPW3b3H598RmtAE1X5Gpwp7Ny2p3kzSfg==","shasum":"394dbcfe6511e66cf20e2ddc9ef0fcd2146bf297","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1604106530.0.tgz","fileCount":8,"unpackedSize":566518,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfnLnECRA9TVsSAnZWagAA/28P/3SDkqLNjMT88gE/nmnr\ntzuJKe20dE818coEmL7htmZ7ebP7RX4ypeMbPijDI4Q6ViyD4vsqt7Hy+Do6\nXA+PLXIBqPEv+66Ov8Kxv6elkL8WVnuVqAViNacfsJXBhW6qafZYGITPKCnF\nATx03cGf4K+uKNkqi6qi9IX8HAdMZDK2VQBvq9Uq/Dw7n1wdtGtEvBD3Q1S5\nFcOXOBfJlRro/kuUueisXjNORT5q5qx0poN0F9QGO+pMbWSdEO4vPcHkkmrg\nBMMJ63A3u9mxox9eGyyAmWGHlsdID0tGPU2QytnpganHjldKw6d8K1wX/A4N\nFjvN4qNXBME+bKWzgvM9IOZFYcrc0FFCFGa8/bbIJGll6xUVRbiUmWr/5yOl\nJv9p54EMEQZIdZ1BUvH1JMxQiGBidnhfupmOmRryJGy9A6oIvt92gM/fxT4E\ncUVbAfrYs2RwdXoHNnWoCCzpVJohclhgzdQu96ZPJXP4dB87V29SMVU93YKV\nmmB4/g0DwxfGY/KCeZYuAKC0PNjzOH2Q+pns4kgOGo+cnbGy+fdYAY9Tmm11\nJRKrtCOcy6NTNP7cL9ts06VSadPf/RmsfzBtz3PRc9mRpJGEkYr409rdW2Fq\n5Cq36XtURPyo0DtsVfJg1QbtbhQNhHTQMVgdcmAxDHc/JvcLhkAJCTwZjCPo\nO5o7\r\n=NpLz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA4WK5uOO/xc1gmIq2kPcPCNBP7kM+1cEQnuk5z1RsIQAiEAhd7kLbnddpZLyDH9ZAW7eBCGMcEeyqfFOeW4rwH8fmc="}]},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1604106530.0_1604106692122_0.18304482004757894"},"_hasShrinkwrap":false},"0.3.1-insiders-1604576237.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1604576237.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1604576237.0","@vuedx/template-ast-types":"0.3.1-insiders-1604576237.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1604576237.0","de-indent":"^1.0.2","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1604576237.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1604576237.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-wUhMvFTaOAEbpSCuYscqmovsp0maObAj7Z0eHbUL4968YAmNpzKrSx8aYHPNYjytGdvTy0ulqJoJkdFA3tC8zw==","shasum":"821fb45dc8efe993222fdd928c512c93765ce0d7","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1604576237.0.tgz","fileCount":8,"unpackedSize":666547,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfo+RwCRA9TVsSAnZWagAA9nsP/jrOJQlo5yeBNFSh69OW\nHALDh+rs+Tuu5i+dPBmbHyUYOf+bSxmk2Rppd5h5Pz838XInhDXhXAp2Xvg5\n7PGjdHMTkDKKOCkgBwrwcouNmR09EZ5nHTbMRVQyzOjjv10abYn39UtasWlT\nYgraoxPU0H6nyBGElh7iXi82w0m8+XBeWAHyEv8RgXRh/zY6L80Q8Ce7sPib\nk9sPumHll0btrMFia00aqED21BI0IpdgT0gT3ffF2fMsZc3Esy4ZE0WWQKtn\nixP0wYrYyErm5RZPmDposB+60uD53QFw3sKE9nH9bsF5waWkBBNnlCFqhJle\nnsFaTl12tjeXVEheO2FnUP17RRdpwGutGDfxA4hb3nsBP1o6fA2OyR0L9fb+\nqqRumE7X2u23sME+Rb+4t9MxGNu0HOCwmUKggDKUBq8ak9rdmjsulnp60NPZ\ntWUCBBoxp+FSqlb9E7kj+LeqOe6x850+BZtVVpnZDq7lWhpPHroygm7LKmbd\niaa8QmLUzIJ5da2p0rlg/QYtOp/glD32Te18L100fgyIyWDlK8d8br0+KGuT\nBAUG9mGV5GbHJB2t6ua24Mu1SZiixHGyGkf8qLMIFWi8Kdv7hptrTMXzIoj3\nqCh2x+NvCRQjS+xxFZH3pWLGqjlNSDK1RI6HpcVleQzeFcS88qcCZT4wjQig\ntxOb\r\n=gfnR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFy2XhB2FHvWEv5MGPnmquUZFPShqV2ANHBT3Or5J+2ZAiBgj3nsCVwOm+RGOwmOs8q9d41+aDycvh2G0+HXLIWylQ=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1604576237.0_1604576367907_0.6117137478645902"},"_hasShrinkwrap":false},"0.3.1-insiders-1604891675.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1604891675.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1604891675.0","@vuedx/template-ast-types":"0.3.1-insiders-1604891675.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1604891675.0","de-indent":"^1.0.2","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1604891675.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1604891675.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-p17e0drfF+wji41ag88bITTkZ9HlfG4VNPCgPLifb0b907EWQwWYDjgUOHqT5j1Mpdo6a6vZugyZ9dhcmdueuA==","shasum":"c7c81c1615b757329f9f177332e7e36c0bf4c05d","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1604891675.0.tgz","fileCount":8,"unpackedSize":666547,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfqLQ0CRA9TVsSAnZWagAAQQUP/Rsp4AdqPzToyZlCDX5f\n+5oQjZ6wjKXdKG2NhRzpPAtroxqCpKy5R4TC1tU+BZP8BA8Cjj49/vD6bGKN\n8PWdR8OsbCNYt2wi/hLb34XN2P4wfmszbg/epP2jOf6+dxiW10ZjfXMVOM7Z\nAQpdv6CpBCA51sebIdEw1FwLwLH6Ylq4QnWcwlU0Ysn7+wbBbrTL6WiAcC7H\nAMTwbSaIo2MYiXMJiBoMfbAUIZcnkAn+2se1SROg8LMfwaI4SseEejoAiT9g\nbieW3Cr9XM34mHnwip7sD6GVGJUcY3IOyp+oleBtOQ2xJV74/HJhC3v0DTDs\nvMD7DjMqzYTGHUK2uxl3PpDgFYmyWc0s+4JOKxU146DxTHgJhFiHCorgHlGa\nhSvQHM7S/SqlCb5KZOL1/XIc3LAiDvhJLiGN9b/hNsUssvwUJMx6sUnrg4Qf\noyRwZLnS4yJegtsgatxMcta9YQ3xqlz8i0gSjcs6dVpBsUImb+OvsBmwMAKO\nSkHucLOHLRgHJqIX6UZIY2Hnhm9SVBXf6BnPs+5JigI7Lcwsi3JQKNUek+8F\n+FMLnO7FXnfw4V3w3H0ONPm4YJUDkURgK03Wu8Ac13EdyYH9ef745opMEg2D\nDpfwuDbWoS8QLbo4j+z0gwiFOZCqRWSKC7lDrClCAjEfniaRQL7bjdwp4oou\n2tB2\r\n=bJFw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDD+sCrfa/spjtm+HnwSmTZoXJxXjs27La8kJhBa/rYTAIhALVWewFOxzk1/UjjF6/v/GPuPsX6vjxbleUW3LNs/HEP"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1604891675.0_1604891699824_0.9194152925941548"},"_hasShrinkwrap":false},"0.3.1-insiders-1605496438.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1605496438.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1605496438.0","@vuedx/template-ast-types":"0.3.1-insiders-1605496438.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1605496438.0","de-indent":"^1.0.2","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1605496438.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1605496438.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-Mz8AP3HCc/Yk3NZ7lH6do2rEZ68SmeqOSagju/TB9iPK62gmEVPylemviOdhYp8y14tBLA2zVHfXf35E0JZboQ==","shasum":"8eee1d55a7381b7040f09d3b21b0ef9af0cc2c84","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1605496438.0.tgz","fileCount":8,"unpackedSize":666547,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfse6RCRA9TVsSAnZWagAAkYsP/ixgCu4E44eFA4RktPF2\nZ3Nh7KR87P+8/BokV/VU2NW4cGr99tdz4jRHAt/YxUfEZmjpIlvQzZlbgElq\nvB3wyPPSmK/KHw4FZTqaeeBQvw2Em/AE3Gp8ZhwufTpS2sjir6i8k8zJ6jXU\nrtKji6eWLeSOkDxaoUnm1SzBvbh3xxav46KonfEUQ6kGF86o/CIm2Nv/o4OT\nsvy7dojc/31lY3SNupjOq2mX8u0g8ucucL6+FK3VMKsXr6kuxO6ktxP4ihax\nKPphne4iqkVfmP7aZ3sDcGa9mUFZwMg1oybKYJY559YCzJ0CSgEUb6vU3yNU\nTZO475D4RwojaE5vgHi726lG0Dfq6wVKGRmFBDiQkE3V9hDSHPKx6yERN1S1\nV7EmcbZV49H2tz45/4fCeIxapz8fiXg9lr8v3oNVN8h93yLmMSi7gKwWlSoc\nD8PyKDINP0rE0dJMFtqlZS84PSloNfWAzBQe69/OCF8yoYU248AYvCMiO1zX\nCG2QBn2Xe6FqZcYabfuKnOyLDi7UGrNWy/zx/lE0ESpCOqnodsDi5UtPejew\nPETtZSH8W8vI8xzzMeO13K1AFYcTW0XxcFR9VR9a93fmHW2kZG8UQqaqbjl8\nbYSc14pfhQqCOAIv9G1VRrbCNXd+1l2feo7pnl3gKvXWBy1rkk2RQsVVIka6\nHWel\r\n=+DCj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGOk6P7WoDLomEFnStPWITTayhdyo6rb6ajUpcn7z7xHAiA7RKo/rkgvFePcKL2+tQ8lUCdgTsRtL9+2QWH+3cZMFQ=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1605496438.0_1605496465142_0.753152797101029"},"_hasShrinkwrap":false},"0.3.1-insiders-1605961078.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1605961078.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1605961078.0","@vuedx/template-ast-types":"0.3.1-insiders-1605961078.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1605961078.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1605961078.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1605961078.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-R1DwfB/gmALMlYP/t3xV71ReWTkGjl6g3HU9m6DEciKon2dDxN5/ait4i/8rl8SV3Pqh61BTQm1KxTzkoB4qiA==","shasum":"451ff1eaf99a317f29aca32fd6f1dbd17ea99d09","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1605961078.0.tgz","fileCount":8,"unpackedSize":741817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfuQWUCRA9TVsSAnZWagAAmoIP/j4brAFtYKjcw74iTg5d\ngKu54P2GQg1KMPPagpcmXmfyxSBhGzdX8KpX/6R5AsaRjBfP4cV8FotAiNc7\nz7FdqkSrWl5ElIMR2vC8qIexqnaxFzpT9+xs1flWJuvCpmcGU2PEN5WBcXq/\nAHaQkM9cHjCPeALhRnKS8xs60oUMyCfdo9XK4RkryBhh0b3onBmdKWnb7f9S\nvb71fm3uAW916cO/+rkrjQZwW40pB8FDk1T45nxSEJtqP7TN/SuYVOZiHsNq\nb74SfVHSEI1Su8T2oJyvc8UpgTVLLo7HG/9tIo190MvKDeTS2KS5LuG9QzQs\nLMISnRL62p41jBx7Ue/eueCOPdow/k1W9WU9S0R8LZwZdsJ4oX/MH+2FnC//\nkAsUWi4vPdUF0Vw6yiVWVhoInzzkutNRUu3ba2sUZUjGzYJs90wmMzz6SzQZ\n2iamiZjyWjKr4uEUU14JpPGsAf80Zd2fsKc8Ud0RNGwmUDK9vIdzaBlw0Fvu\nDmD2ifrpTeBVVCS8vWpNZ4Yx1to7bP+FtYntABAi8CrmCQBxVyv59N2CYOwv\nmQ53a4fDgyfLwEJIA8ceJLyy7cpLXW76qBHqkVp+t3bRvqDevECNVJ0JPMhN\nO3WhraygMJOVAmIsodVx23JRLBemL537mBD6U2fAbT4HZlm8hBd+CKNycE7G\nOgx+\r\n=1+n4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH1HyPJEsf5bHs+I+gTfh4uyK/c8ogh+WbSrvLKzaYCqAiEA5+J0A99GiGIlC3Yq9Mdj1EhCgIZ36GezLmoMyrElsSw="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1605961078.0_1605961107750_0.7344179136972571"},"_hasShrinkwrap":false},"0.3.1-insiders-1606047354.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1606047354.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1606047354.0","@vuedx/template-ast-types":"0.3.1-insiders-1606047354.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1606047354.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1606047354.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1606047354.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-3hWiJbnf6+P4rt9NZjaAZFnMxC+j8dlcg1xx5O1AayVC/MYtCX8N1Cuiv5wOrwh1n1e+2nkgWCyG9ZVwPpTQXw==","shasum":"dd5dd509e235410b4670bf6ec591749eeea8b0d8","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1606047354.0.tgz","fileCount":8,"unpackedSize":741817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfulabCRA9TVsSAnZWagAADFsP/iuPJO7n5noK6f/bRRsI\nQmD/UnucJ7xEcW62HniP0G5guZH0w26F6sL6XgO2F/v9dkMdoA2gA/ib91lm\nn775uEReTYIiObr1iMuPJiP3rE7e0GdBE07ZSDXNl0HvhR+MoSUcyyCb3eLI\n3ARRhnPLSbC7MYrX62OlYyePYT9g6VRyoiyLxhDT9oEpn4gpZepicq6Sd0+D\nWcvDqhGPtennIxvgfI/j4VojZvEaDjkadPHnRSE8tje/DyW0YQs6gLo64YDc\nlxm2imF+vWVg3FQCy3wudXhbjun9Fo0q7+s8eQkXSdmf9DJMIE/Z4l45ePOy\niy0nNRUd8MPWqhm4lboWa7hP1oR12I47D8hfhxIzvviTuffBUFu85k2YUW79\npX7T3waiGi8OimIlKsxD1zjuF2S7ZYSEPaVE57SNoDDTJhvangx5BkJZHSyP\nIeoY4SfkP7O1gZEFhWyco014N24xhEb7hxu5SQsWy4XYW36+AIPvNkcJ+hfC\nYqzZ9zXr2X32HI3Hxl9I4v1pT9hPipbstU6G5flcFVyGZC8EcHXEmMYKTHss\nu3ux+DMF+DBo0os1TQh+JwE2m8ilNY3qO1QqBFcSLipbOEIkpxQLza9o2thc\nNgkrtulC+eWe4OgMSerbRgChhQYP/c8mQG2KUhFwBf/N+SSFvkT6iVB9a7O/\nPYaT\r\n=nLMc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFwRJ7wBjR9Dsi2V1jD5PsH8Q57w9iwtPWCVPZLmMicGAiEAx8B8dtRbM67LMUrGebUCbdyMIbWiwveh3LAfQBKEk9U="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1606047354.0_1606047387300_0.6122997381858386"},"_hasShrinkwrap":false},"0.3.1-insiders-1606101276.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1606101276.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1606101276.0","@vuedx/template-ast-types":"0.3.1-insiders-1606101276.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1606101276.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1606101276.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1606101276.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-1gPNbEfcJLA5mSveGb6F0X7UK1pASSSjj3+gfSctNRQqmwuedW9ZOyxBFwX9FqpKfmmh98xbBqNMP9UWxJRghA==","shasum":"b43262fe8cd657c4d85e15199e5cac3b621fbe61","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1606101276.0.tgz","fileCount":8,"unpackedSize":741817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfuyk9CRA9TVsSAnZWagAAFewP/Rge9tA/n3I8s0tGigx+\niOsHnzv/PwuxM2VsHR6GiVonXSc3sWpdNIvbbVzaTOp83gA//3RlryWMcG7z\n9/vk3ozQXyGg1Dhj9OjtYjl7xcJg/+3bYGbeBICyYe4kpvwQb7ZInhxSg0Zs\n7ZL85mZqPojxbyS9gUnfjYWtlrv3jvqKihoBb+2A9VmiTJ1SYCj+2jqXsANj\n+2ej6LJ7/CTZ99GJDCoyBVXO8mMj0FsalvCtGRju8KMTd7So6gCb1CEyLK2p\nMB+LR1xyCxUL7myshMZd8Ul36DMou7/ybt4K3FgTEZTDj3xZ9jS2eS6rs5pg\nYjbavhf+svCO/jq1jZxjZcO+3QTnHQ8em3X09Cbh/yj+8lO7XmKWQDof7m1T\nRsmjNxtIb/nXuICP2pqiE6z9PWHy326MNRago6qzFAU65w01qKDXaf7pysox\nKwZ/LDK/ukXX2C6TCjUF2eTWxlmkVd12pXBNwinJfb2nOt5ONdXjb8e8h3zB\nfTsbP2JhCCdMQhzL8V3efOmvx+4mu/04DFI4XmHCyorFwcIKojsW/3Hb7PXl\nYWlSqubviYIiudNyv10wjQqApDJ7IIC5MFjINSrDCOpp05FfJVRgSKVW3OC4\nQHmEcohwzhJthc9JtFKddI1891u4cUjJW1OGaMpKJczqUgKMaax+fmi4HDXp\nfEqp\r\n=4SmS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDV/c2W5ymqijJq1oKxIuBIHOfmnEfzy23wZzYuZlShMQIhAJo/jL9wqNUaUzxa8u9VqRh/8tcTq5plG7IU1QUvm7hS"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1606101276.0_1606101309618_0.26406296974296084"},"_hasShrinkwrap":false},"0.3.1-insiders-1606300525.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1606300525.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1606300525.0","@vuedx/template-ast-types":"0.3.1-insiders-1606300525.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1606300525.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1606300525.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1606300525.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-8ArGMSrr3GeFG5lVUI9y5nvFIy8zBZyQvC9KkFftchdgv7eKgxKz2aVk0Da8+NSaiukDGD5Sz/+IHBZsLyVDaA==","shasum":"1853387f565fa57b97ac99e9d61276e891075ba9","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1606300525.0.tgz","fileCount":8,"unpackedSize":741817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvjOMCRA9TVsSAnZWagAA6ewP/Ard/f6y1AmmVeNVS/D6\nMYF8eZYVaoT0a6PyoBavcHVQRljQ6sY9SjujwqAdTeCTF437CabpHzqACd1s\nbJJdUTOHjI6SlZtC/sv3FMKblEmJQWvWM9T/SEK8Vp0a/2VKt77PjyM5mflq\nHoXHvTSeKRJ/Hf26if/twXWDeJxY8kCQzhjLShWuZfAaIAjF3wuaFV2wXaU8\n6vi7N20PJab2/UClRPTVoGuudJg8NwIyE367EtqM7XueSwuPs+vpq7qLNzyI\neOAtFen5cy0dZNwCdaJ74PAhl3BETK19jAr+vWCRaqZCRNEuB3hpw0qRxS4b\nd8GUzHlQVoUGudvvjcdIRWVxMappuodPCliTWkXtd97TBMAHS5FIxieHDqTp\nZdK3nyY7xfGOmjCzAjGWXvj783SHD+0m8DLf3tXK1D6kLdXHm1nuZ5mOoWGU\nXBGQPyNz0FG7ANpZHsGaFBpUKSd2rOjUfgV48JpaPSBGv0P5KH9RgMCgdxge\nekVrVm4O+ZAuz7jOP/kqZ1V/mHtTmWwiAVAfw/Dqm3axk+yOlwRRqFXvH6b7\nWuitH9kCC9qUaBKcB71x6DPF5c3DvJWy3mGbHz+yy2u1/tTVz5ctbv9urDyB\nEdFm1FcBgHyNCyVPnUsoL9bW8Qc/BxCBVAe4Tz33BE5ch5baScVzC/hgcNi5\n4fBg\r\n=srGU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC1q/m7b6ziRyR5kf7cgSEp4UD1SKHvXeVo+FxksiepYAIgHNVPFXAkZdLJj5KlHTpyIz+2CUIEjepn4totT9ksuSE="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1606300525.0_1606300556152_0.8428128214830424"},"_hasShrinkwrap":false},"0.3.1-insiders-1606311019.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1606311019.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1606311019.0","@vuedx/template-ast-types":"0.3.1-insiders-1606311019.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1606311019.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1606311019.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1606311019.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-zyJ8rPXNOMKRiwZHN+79pKPJClZYtc/JdUZ15UcRxDkRc2WWhUxkVQg5JsQn0zhSt2tCzVxGtIbF9xxm2zqh7g==","shasum":"210d804e67e3c24ef61d617353258628a35a0d32","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1606311019.0.tgz","fileCount":8,"unpackedSize":741817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvlyNCRA9TVsSAnZWagAAkKUP/2f4MMrnbtHB6Sla2gkh\nr1tFRfBS661XQ7M3wj/YfYgjmApYz0Fmmjplig38YmE5vihgpBIQy6cBQaA4\nJb5QySLOlO5GpmdRSDbGNa04mDb4pj2T+1bgEGybEbfZypgbylxXl2/nFNkT\n977S7eCCYQV2lxX+PdQenPuJCZwL+mnmayNyxHgq538qkWGek9aHpcE3p7Aw\nNIYsN00ddU3gKfNb8R1yIYXLkkVCJbDlRDLaHM/w4fq7sgHUl3KxnlCCCRDC\nlLep4N09P9INzlt/IJKLkrhbE9m5sWmUAVSkOSorPL25QfMIRbaSIaH9ZdLd\nfVvoliPq1M4LpxQxKbWO932fx7G6kdk5Z71TJaqUWzmndNbJ6qAGS04/xblY\nCvhfwbwGy5W+gYqAZhBX0y+iBfV5B0xt4RBtRKoS1Ejbwa/BqIea2l1U5ah9\n7bfMNv3UezG/hGkkIcSWjesYDI74pPp6l4HIa/JhXrfbsxqW/D4msUb7pjUO\nEL4gc3OwcrHcwbG8kCOYc3vgBVRz9SovL86BflE3KXNkpOLKUvmirbjiPFCO\nCfdNCwgXfJ/ZiGlsBxXQrq2oL3cDO2BPdykTUIMulw20SHWmlC72vz95Mu8U\nYnF0eF880F6upXtRfpR4p5YROuiidoSR/q5ex//TCPn/TRWwRIiuH9I8uVrh\nbALY\r\n=wFKe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDyjHK4QeyXevHJpuLQ+AjCky64BeRURlBsC7oEflgy9AiEAuBBhISVWU4TIwdwpI0BrOeoHphDndIaZ2p14Zn7fdG0="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1606311019.0_1606311052547_0.23044593748351616"},"_hasShrinkwrap":false},"0.3.1-insiders-1606467106.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1606467106.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1606467106.0","@vuedx/template-ast-types":"0.3.1-insiders-1606467106.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1606467106.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1606467106.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1606467106.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-ukabB4KlJ6Bvzf8I7Vu2hkjFEEf0kQp5D85/0R8DY4Mhc6+EW+vUyAew/2nfKO4HVUatMfsesdCz+quYgQv3ew==","shasum":"9616694ac82c5fcfec80e5ab5f0115b88dc9819c","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1606467106.0.tgz","fileCount":8,"unpackedSize":746839,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwL5BCRA9TVsSAnZWagAAUCoP/2qx6bRArlY6UCpVrBg0\nHTWaoHPz+a2U049nYaVJwk8xvprbJE0hY0mUt1TdB2hLcMTbrPbuG023GqZe\nPaZ3X4wNFuqoccpHtqvJIo7NXrzimZhdhktHRd2eJ4DQmmV8OAPISIHL58MX\nkgfkn68klAAe1iyNrdAJ/YFrxCEPH05bQbvgziFaeQrSGnNi604ZL5MS+HCw\nJioq4MA8gZr9VoBLKfx5ohzE/VlIodrYP9bumZKzzMz0s3U7Y8MUzvqvl+jI\nmCtfbP+bo1Su4blsMOIWElY0XwWMtsxNojv8VBzr5uUoJZDXgzvhTDgDcdRr\n+hsvxi5ZM7DxaObMW3Rn9l4ss9nFOg7CGxRgJglBxdovvkkR1vreAa4mER95\nyPe0rbzrWS+t5E3zoFLqGAjdac1qlr4lKrsIQMi5FbyxzFHJR0gLgBWrPC94\n6il0/W6g7dQkcOs/uEvZLZBCqg/7qDScKZ8AIEXqV1LDcEbZ+6fxWxW71IKt\nq1SQ53j96rB+XXQvmaQZklh/bsc4bNUf/domtifnkcHyUhMeFVTAxlDCLXRO\nP8brmGGET+fws1SI92zZ3LpKfeuyM6brTTUK1Aa7NC3PWiYlYHNUXJglm707\nS2J0A4Ww95aYbrFPkUuqirekhMy/7MwH5OMWR0CqF7c6vn/wwb2YMOfRo3oa\nlTz1\r\n=N4KC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD37WBDNyJ8G/7whR3QVUb0I2qSg/0ZKCh++XMcqOQC+wIge49y+ZvZ7swZ1uw1gyVkgV3AkWljG3KE3t45s8IeTdY="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1606467106.0_1606467137381_0.4281226195001504"},"_hasShrinkwrap":false},"0.3.1-insiders-1606884529.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1606884529.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1606884529.0","@vuedx/projectconfig":"0.3.3-insiders-1606884529.0","@vuedx/template-ast-types":"0.3.1-insiders-1606884529.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1606884529.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1606884529.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1606884529.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-eevKuez+KfYukxMaHp06nzjpfSQfcc5nyAVeUCN+Ud868xQH3zPcJ1wgnCOQXzWpezsaIkwrdLOc1xas6YsO1g==","shasum":"52dcbc37b0930ebc298640dbd5af44ec744dd96d","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1606884529.0.tgz","fileCount":8,"unpackedSize":800373,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfxxzQCRA9TVsSAnZWagAAEYIP/jrvxJZu9IIXG/SnMk9m\n6sG7ZKX34GFtHI+YV9/m74U+EDHPXoTUL0nN7CV12Vu46q8QiBiWreRD2grl\nDxYt5T8DguRP6gUC+v8O0okSwvpED1UXx0158mwf0Q4b7T8S3wnuASqxi3db\n66DOKFV4s05B7+6jGH2bNypqTyWM547w5/iXf0HKhaVcDdvJ611EKbBIcxFb\nfChZixDz+9bG8GNtsEPfYp7H4Oa6iLSpE4GqRLo5H6cA0m9fcWh4qLVVJk8Z\nEQGQPd1RLNDlGXIWn2iZ3D/11NdIhTQyy65AQTTK/A4w2Ivq8/3jY50sL9ok\n0gqYo1Z8x8LMIcpYC6WMDdb73H3s0oGgi5dTyZ06FIs+zXahZjTaE4Vj79fd\nVnpRQuza/jDKAk8zmikGwiFQkbXQoFcB58vbO860EeP+WNewz6wC7o7m8cf1\nwvUXdRTk0ogNdcg4kC2zkJRQ/b6Rc/CNZCxnlq/4YS1yS8VaAADsSpVp2y9j\ndT5rQBP2x5Tv9UvKFTSRTeuJ+WbCWdcgPehQLLLjCOCPHihkYezPm3XUHgjt\n9iHqVLoruM6w4e0FhpQPdQcyGRn8R4xB67BF9QUxncJ+karO8BdAbQFSFbIt\nFSCTOupPblvisR7DruAsZtNvozie2mr7pEp4JNk9gZDOjW+s7Wh5Dl6AsIOh\nlnpW\r\n=kwtO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDqTAwz4DunK0T3Nk2mKNFCkFo9NC0/I+SXtIuPuiO1IwIhAPfewVVBAJGVelazoD2xTSCzUFWpvgo8lpZD1IegiZfg"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1606884529.0_1606884559777_0.6454135994154102"},"_hasShrinkwrap":false},"0.3.1-insiders-1607121235.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1607121235.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1607121235.0","@vuedx/projectconfig":"0.3.3-insiders-1607121235.0","@vuedx/template-ast-types":"0.3.1-insiders-1607121235.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1607121235.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1607121235.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1607121235.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-O/Kw7ZOKDUF4NLQdF47RUWKYPyH8AszuS5wWStP/K6BylsGN9RvwDtk71BymkmTZGK8H1CSLS0QHw9KaxNundw==","shasum":"93e7d1fd7bcfe10afa6fbd704d5f31ea7ba4a074","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1607121235.0.tgz","fileCount":8,"unpackedSize":800373,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfyrl2CRA9TVsSAnZWagAAzwgQAIt4la5x0VzB53FK3sGG\noJvuwTrITVrvWpn3VCtr20ZJpx2592W23v4xi4z2KIRsQfMFsFDVbEhj5Mqk\n4/ul05W8uBK/Dd2W85WgUK0gMOex7+lSBw1EO22BS6cR8tzi94K2JnjgR6f7\nj7sbKwORZNLWGvmgrWTF0rF3Aen70zT88lKVTko+91QxaGBuWo8TTKpJC+hy\nAmHq3KonaI/m6PfhkHRiQIBjd0USOaNfL1wzlp/9hc9co5DOuwHBzN5AP7Jg\nWuFR+MNITO9ObnWtYLEkn6v48LFOKZW9bOCwC9SZcbtHRdlRT5ymAF3swfWo\nnTNHN/XOm48bntg6XyLFq1USiw0/Tv3tkmiToXwJMsI7IZnkSukb0eEo4vpX\nrH3q93tGBexA7oj4N8Gp+fapytEHtxFmtlAHqo3p6x082sv5qSThZcLwnVlp\nCc5T+kHL2cmpXoIA4JyyLWivIxRUvOf/sxb/tvYpXN40l9/RhtfIiRCByXFY\npt0Uv4ddvAZf5cdB3S/M/VWU5Xjr2/vuKRR8MQwtgpeQ3RBSt1fxstAae0uO\n3+YxbPKJQHSu6lghZx2b57q3AdIVjeSOlihwJmu6QMmNeGNzE6+kGvlkTwXJ\nGv10cwGK5UmFDlR0rWh6or2LBchgi3fKgy96GE00UQkVZ3LUNS4CKS7APJop\nBO+Z\r\n=UhZ8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDcDPLcn2zYGaQgAndakv4VbsvX00Kohk8BKJXDr1wZmQIgf2d5+gHMVjay2IDN0SsCKzDb6+Y42zlVL7wm57RDEzw="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1607121235.0_1607121269816_0.5411238826228151"},"_hasShrinkwrap":false},"0.3.1-insiders-1607543873.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1607543873.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1607543873.0","@vuedx/projectconfig":"0.3.3-insiders-1607543873.0","@vuedx/template-ast-types":"0.3.1-insiders-1607543873.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1607543873.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1607543873.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1607543873.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-BpWIzSxAn/beqTq0d1iMQRHyJe8FstyyGD72CzagIAT7WW1VRYssA6IZqWeoyWWAfDJ4QZTUXO/Xy3XktmTOzw==","shasum":"579d64fa4e01485c96dff20a94a90ab1d0470687","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1607543873.0.tgz","fileCount":8,"unpackedSize":800373,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0SxhCRA9TVsSAnZWagAAOr4P/1xAsdEhLqTZO5rBZDEK\nk2z54igWNGMUjPVkR2b1d6B08XleiLrLW3XOd4s1etDe/ZoMq3jfXvbwiWWr\nhlm/Jm61qWWXHLZAGmAMlkOn37AnM5UORzZGDYDIjxfKZqX7e1g0fDJNuHry\nMiqlZdhjhGWd/lDuWPHdI/4y+5/YuYEnnDCvoOW2+sw3l8Bits4a0uKkXKoQ\nShhrpwvLg7MwMpB8+6o7972fFzTphdIzPFZwU+gvAE7uRW+GwiaEvgr3EZGZ\nZeHGpoj2KWuYoGV0evhRj0gnwALZdjghhHkp+v176eUB1cRDI4mrin704XKE\nTShsKse1kS75COpMESiP0K/Y2dvPdIlKX1JHmrtmwQgR3cGMb3PYO05GCh+E\niiUXQTEbOBULi0zXZymfh4vwefFlkAkhyyvpNgcXNaSTRBXjMvQna9iXwwG0\nrfcek43Us1o4IHLd9e9xbskrqyZAvsqrEupuDKP2TzNYqVGCm80vx2Zdbv+I\nAMoBl4K+iD9Upc/P6VrnKDEB16xJFE9v0+2FQUghFdSOTB7TawCFPiW7Nb/d\nNDZCxoQob/5tomf9hg5sEADcLOSRpyL9arjAQ9+PnCwzxij52Gln48+Svgss\nVPew6q/FsqzrTVbod0m7YSsnu3fMdUGDHKjjQuFlDHB0NK6PYwxfpfokjd0C\nPVCm\r\n=InAo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAkx7v04YMjgh4x+msB2LDv6xhDys5syNUr1mxBnVHLBAiBxIeq34xg0BKGQTnARYRl13lzuqGvWK7gKbnHfVIBmDg=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1607543873.0_1607543904486_0.3156648701310625"},"_hasShrinkwrap":false},"0.3.1-insiders-1607576406.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1607576406.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1607576406.0","@vuedx/projectconfig":"0.3.3-insiders-1607576406.0","@vuedx/template-ast-types":"0.3.1-insiders-1607576406.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1607576406.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1607576406.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1607576406.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-PJIqmZc7NHGzsr4L5sya0tfoseSEdwwayTkTXrLNJjuG35pRGjmthE5WJ+dxQueUEDF1VBQhVotWNgtm6rMssQ==","shasum":"b0fe4e7c508d37b8b4f645592d813b4c9ce0ed77","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1607576406.0.tgz","fileCount":8,"unpackedSize":800373,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0at2CRA9TVsSAnZWagAAazQQAJFH9LZ5PmC4qDADc+FS\nEXs5gUfaVX8sHnVDUK5ZCOpCP2WdT0VQqvKnReF4db2dyff75bBM7ifCaMxk\n3fOL3tvmmgyaZLeEFAEmCgQKJEoOjxUQka5w6n5dk8epDkEz4m27D+9see7E\n+Ix5boIoS/z92oWU2D36/T9MYyZ/3qyohzch2TC0/2/t2d60g6nDAMwZdJ9Y\nOmJIYNohD1cAjnjmd+ENa61psr4ThNGHZKjnBO7ZVSvxZLrL4GoOPqq+kCRm\nv6Wwuc9gdJ5S3a+8+Q6uflFi+cyQ4SR0Dv8QIz9W1g4llRIt8cWWA2qb6CVq\nSL8w8H8AOKfPy3z4PlFQHHqfKYfJerKAmOQ7DPSjOx1tUftn6jY0abgQG5IE\niDWmQjRfvOMP1PBgvKB2OWJzXk9tf6gins9ldawv/Ep/fAbTwogMGJYiirhQ\n0uAfkNva2WZFIf5+bC/a8fmCvJ+URasXZ10/YEHCFOuo+mPwDjoq8gHlYoCG\ntXlOp6coH7L5PwNkX0W2TDhCAiwVPh13Uzedw6srVVHySwKh8PyvYt1xhFpM\npztkUsmiTouG3eW1TveL0NlIw1MNGozu+A6abfdezL7Pv5qLE0FUxXQXs5Mq\nue4zbHzlQJQFF97edIDI4Nx2zpJmtX035jASnM5F2ECu2F4Zb5CMMz8rlS8g\nJ1UF\r\n=+N2V\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAikpo53vLAXEmzdaIWa9267ivCZcCWKsamXCZhcjUA6AiEA1Qd3aPBTWJqM6MYeOK7iT0IBPpqU97VGucfqmptgZyg="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1607576406.0_1607576437936_0.04891547219058334"},"_hasShrinkwrap":false},"0.3.1-insiders-1607576746.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1607576746.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1607576746.0","@vuedx/projectconfig":"0.3.3-insiders-1607576746.0","@vuedx/template-ast-types":"0.3.1-insiders-1607576746.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1607576746.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/compiler-tsx":"0.3.1-insiders-1607576746.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1607576746.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-0SyXKCCFDju94PV6xQkQzodjNw1G8MppOKCUE3P6neZf6hyKFfGzGk+e3h7vqHiTDIAwE8JondDZZLlJMK5+cA==","shasum":"97de314c1510de16380cdcd9aace775a2f2da1d9","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1607576746.0.tgz","fileCount":8,"unpackedSize":800373,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0azJCRA9TVsSAnZWagAAr88P/2YWBbu+g4E/+vL0EtYc\n8Z25+Odhsj6+AWwYUmbdo3/SkSe3WvEm53rIjhitZrsq0+esJFPG8fMP2QZJ\n04h5tZvdQPwvgPrhQ32odjU6gDHAUVdF/g0WX02sTj3ijmf13NfPw2GcAuFD\nPekY3ZEIhNuW+JaMPjopwJrFctbvkEkJCLMuukRdUUN5kryraEwA32UKTV3O\nEdjJDxqMyfroMJayaWLQ/MhGRKrflezwm6hMxYyFmgitae2n24kRcZ8c88KI\nRriYJ0Q3ifPGHBI/I3X7ANR52afxi/p+ZqTbfOrOTBm+8/DX7FpKEXKpqzdD\nvXpJ2pGkD60tX4U4+AIP270GBObqRHE4IZEfLH7F1RtNIpppOEPdTxnSTpVb\n3NWA3Bz+zR1fdeKI6Sa8x4+zowz2rODuMnmMdMIY+weuOSkZofZfzw8T7xcn\nNKwHHDIHRxAS8/De2kUkI0AAqCxqsyMfwnonKScLBM87AUEd5WfqVCHUPs3z\nvENhhJ61VZueKSncEFh1e/3O8DunXMk02HSvl9bvyIiJPVVjWLq/Y/3AE3jd\n20m54gc850orAuaGYUkkisz7qdH057yUk49a6W3rhuMTIIkhJR6CtvqJ5Iz7\nswmGGwzTqhMVkEZZ0nnD4dKTWnrUNSvTBrsZX/eGA01OXtJ3Sp0ct/ovj2rm\nDXy0\r\n=tM0O\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICIPBD02153iOjcHYEMZlMwBoCq2pc3PSo23uuHWWWi6AiEAwrrOi2Osou6R92fTMslrXDrlpNRqawexxAJ3PVrR+k0="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1607576746.0_1607576776912_0.8516236909400154"},"_hasShrinkwrap":false},"0.3.1-insiders-1607577772.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1607577772.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1607577772.0","@vuedx/compiler-sfc":"0.3.1-insiders-1607577772.0","@vuedx/projectconfig":"0.3.3-insiders-1607577772.0","@vuedx/template-ast-types":"0.3.1-insiders-1607577772.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1607577772.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1607577772.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1607577772.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-3vb8rrlfCeYFsJwZ+ORA+sPlEvIB9F3KyixFk3f6FH6rpakhD6HTZpzc7iALnHZwrqeos9cEdTygubGtRxSaig==","shasum":"cbc193b3111d7e843e6b2e3f31ca1581309a216d","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1607577772.0.tgz","fileCount":8,"unpackedSize":1109051,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0bDKCRA9TVsSAnZWagAAmMcP/AgmKAJc8wwrcijq4bcC\nGFiN0cuUl2LWXEvp4R7ZovHamCjW92knDsytGViveiov62vNPksj3p4JXZaW\nil7XjRYfMD4zZQyUGYK3Ld2vClrQ43VHWHjppKa4EKMlZw+I5b29Vg9t1ITy\n+cR3em34ZIIS0EzPfkUiagoCoiU7J/Bl5tIBWFI6iBvEDGGE36dN7d/VvvnL\nZqMjMYfr9JQYOBjjiWWyGJyTEdFpRPi+MV1WtPa+gdoC+00LR94mrVP1+dzc\nT56WI5yKMZsMjfEbO5UAkk4Uv9vBffVfQ7sSR840qTbRNUjxMAv+NJPEfnUO\noacNKd/phGEM5i7Fg32l5SScN1ig+pBkWoMjFJH7W+qCL+X3eKlHtPfEAVGC\noHsmUudzL8Sgfu477kwvwld6dYDWJ/yTx/kTBrDb94E/b6mTbFrN3S6wQj5v\nM0mfZdwSW4ObtNlPzibdWpVDs264QpQPLYudhq5swNJizAOAiihW+rGYB3FR\n1oAtUmlxiXS0YEJSB0IJX1n4Eoi9FEcSY0gqGCnBr6pDCIBVkOXqaGndYn6s\nDHOTOdOdY0F57XhDuR+KzSWwVWPMrtCSckmfbDquJf0Z1GYSoOBOGKCTvwcn\nlqbLMd9J2uf/wPfrA8wOIGYcuNkj9+azN9fsJA3ypoMAEQk7GaP+8RD/G36b\ndJMY\r\n=gJtv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDFEOR8+KJ+VpOBwVvoCAJ/KKTMiQwJh6KFJWbsnxCzDwIgdlA7U5TS08zs6+krVNZzfsGH8GOZc/iaXfuQbferwZY="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1607577772.0_1607577801958_0.6911920925765447"},"_hasShrinkwrap":false},"0.3.1-insiders-1607631204.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1607631204.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1607631204.0","@vuedx/compiler-sfc":"0.3.1-insiders-1607631204.0","@vuedx/projectconfig":"0.3.3-insiders-1607631204.0","@vuedx/template-ast-types":"0.3.1-insiders-1607631204.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1607631204.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1607631204.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1607631204.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-rk1rxSgN/cclHk+v3Oi4dbmZlFDZiN6AMr2lzk194s0EGjv6er+mrwIX5dU7r3McqSGq2VwjCAAL2hKvFq3Zvw==","shasum":"8c37a6d1c0e1dc4ccdd871fbf2c68b30982f6632","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1607631204.0.tgz","fileCount":8,"unpackedSize":1109465,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0oGDCRA9TVsSAnZWagAA/b4P/3orIByXSvr26t0Ubrr9\no25Kdimg1zohO7K6VoWFz1JavHIDNKwKoNDTiGXEZ048BhdJZXzC3BCg9+F6\nRcpoEYy3Q3t6e2sxZiw8mLOIEVuFLtMOPUmJPhJ3ScClWsKa92mCmdsYRrkp\nlZujCQpUt7oWzb5+XcyfTpUPM3+0dY+HKwUXbl74rKazS7/sXxmcEAmTo145\nROff4HNG7I7h3rmvrajzcQloJJuXUMYsQsOptXnbwhi4FRGt27Bx68krEjQQ\n3mcK8nfpaKo8CLlHcmNf5X1S+rsIBSbT8cfBhzJMf1EGcjxcL4wQ7PppBsHs\nHJ6SlsIh9grcR67Mk3h5MMmK0YEQYhh0LjbNQaKQK065sg4EvobsYp44/xMl\nsD6CFr7fBe8Chj4i6OvWPOIx+PRXniFTwWJijXPE6Lm2uurY6ut0GECh7I9C\n8+SWsm//W5kIR2eVwEsaB3d6mgI0l4/WNpkmvFgh9i1vuh0rGGifqnIE8In+\nQiMMHniO1YEdDgOsEslLgfUMrILMZA0BB0cHwIs93CHZVtMlVcZZi57X6CH5\n+gcLOkbRk6gtRakuz2WzvtJnBqaldlK+YWpdSXEHPCfzfCKt0DZhb7/nLsus\nXIaaXbN7e+9F/0Qzqw/51mTBk6XZDdD0RJ4Kv/NJvtarXLq7Mu1gx03Qlij2\nRzJ5\r\n=nKiR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+QT71udc1mbfLkKBKmiDBJbaHtlE7akZeZKIDaroxTgIhANuc63mMDE5LJI6mZP4f5ut5w4ycVwf63TWhFdCMJTfQ"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1607631204.0_1607631235131_0.08588312593062608"},"_hasShrinkwrap":false},"0.3.1-insiders-1607632537.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1607632537.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1607632537.0","@vuedx/compiler-sfc":"0.3.1-insiders-1607632537.0","@vuedx/projectconfig":"0.3.3-insiders-1607632537.0","@vuedx/template-ast-types":"0.3.1-insiders-1607632537.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1607632537.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1607632537.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"# Vue TypeScript Plugin\n\nThis plugin enables `.vue` file support in typescript (tsserver).\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 };\n  },\n});\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n--\n---------\n----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue';\nimport { JSX } from '<not decided yet>';\nimport _Ctx from './component.vue';\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo]);\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue';\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo']);\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue';\n\n    export default {\n      components: { CompA },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n  import CompA from './comp-a.vue';\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB'); // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    });\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo']);\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, []);\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('input', { modelValue: _ctx.foo, 'onUpdate:modelValue': ($event) => (_ctx.foo = $event) }, []);\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(CompA, { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) }, {});\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] }, []);\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo ? h('div', {}, ['A']) : _ctx.bar ? h('div', {}, ['B']) : h('div', {}, ['C']);\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []));\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo]);\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive';\n\n    export default {\n      directives: { custom },\n    };\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue';\n  import custom from './custom-directive';\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom');\n\n    return withDirectives(h('div', {}, []), [[custom, _ctx.foo, 'argument', { modifier: true }]]);\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue';\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      }\n    );\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">\n  {{ foo + i█ }}\n</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Convert `<template>` to TSX\n\nThis would get all TSX features but it would require more efforts as compiler codegen module is written to generate JS output.\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1607632537.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-90TmvaAqUk0hDjosucJ/VrsxTwLM8YWHE9iyjMFVe1ddkik6HnzOYokKtfKmofi0/u4Ti/xR3O3be+k6JITwcg==","shasum":"086cfc07374402892f39f027a70f9aa1def480d3","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1607632537.0.tgz","fileCount":8,"unpackedSize":1109465,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0oa4CRA9TVsSAnZWagAAK6IP/RZR0F5s6bHx7sBpcLd0\n2HEFcm3/IxoKZC+Rds1ZI21BNb5GNNmkzJPFSuol/e0WIhHlW5BbYtm8BUJX\n4ITNtslNYw0FGmpyEFhXgw4R5rwD+8rC9k0Vsi9ln18IvuYn9JRomXR1hgUI\nnFKAS80GesDn8RPx/EnRmVClHNvP0n/r1iWApAy5hn0kLD8c/7fPFn5e/gtM\nNnyzzPbZ8D0nFne6kPnSnlBOvWpJqRUmrT5XtiIPXjuttWXgNVGsT1BpkC/n\nnDm+CfqdlVbXDiJJ/zig68Tb8R/LdmZQK2w8GAhc5Q3tybB+Y0dIX2HNbNtV\nVuqMeSFn/uEFbqDQ5hoW6UyJSoKbpEE2+YPdndCdOBvjnqGZ5ocZy9WgSlJk\nLVoGPIHQEjJvS5zvPERqQHyIAoapV0q5nqJtjchWWrLrCxrKsCNvYPpMK/1L\nErNVeHDc0F4d7nzsZVrTDDIZKEtrm6JWY+iGLzfbrkXkbedu+IyBrtT3AuDK\nSTtZ+7Se4+ywLBEPfFBCQH9h/kJCgjnYLsuBG6XiJmswnOllNkoO1E5H8fxa\niqsRP4Am4d04WDlAJxGksbkqhDLzCCWAuoAb1AYiO9RtQsYm/zm2BtRS0xMX\n+XQ0pY52I42bXJ2XdmWST4spbkZHCsxhcL5w3b8vi9neAd4Y2tcC9cRgU8y/\nNL32\r\n=bGES\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC+lah0q/PkVhsnWZKaxtzmzp6PesHFlXXpU3++UdfbFQIgK2FIf86pVx7Nzt88HpCv9HdpdT3dSTlgfOPJYDq1QfU="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1607632537.0_1607632568207_0.3289976939030339"},"_hasShrinkwrap":false},"0.3.1-insiders-1608185511.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608185511.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1608185511.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608185511.0","@vuedx/projectconfig":"0.3.3-insiders-1608185511.0","@vuedx/template-ast-types":"0.3.1-insiders-1608185511.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608185511.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608185511.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608185511.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-icptjZ1DD87XN+DLJHO4uBrtSfOPNDdJ9+mXT3YPCQHoCDNArWW4GnBxgOedlaOSo8xHLQe5xnVcXGRVVhlrEw==","shasum":"c0050bc33dfef270a2026cbcbe44bb3c8a21eb78","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608185511.0.tgz","fileCount":8,"unpackedSize":1217678,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf2vbHCRA9TVsSAnZWagAA/2gQAJ1TXsaXojRr51X9/Qx9\n708hWUCrbeBiLl/zqMAzrrVsJOnk9lOo92KineuMsTlYF1yi3pZGKt1tufKP\nf8YjJCjWwHdVX1AhZIqZbKtnf+abtivvleNPU/F+oKd3rMIdZK/Ne/6B+5iu\n6WxuGyZbyvRboFJGbTGUvmxE7GpnLrIJdKebwXEtRZT7/Y+ux5CsXidwqdfG\nXbFSBmgGWhohm1nNJQCjhlIIjty0CLC8P6AuCK/Hjpt6FmbfYL279BPJX+Yi\nQV+IE6OF4IPeM9oar1UlIU6rUdqzpx31dlMA1iGLRo0/+sbjBXRFLn3Fj8x5\nEnRxg0WAnNUYocZ+aYF40nWvadhPXxj10T5Hmqs6l9Nbb15QgmiVJRW6n+YK\nxbf31RjiJOPcBYMXk1WxjAWofgOvH7KDI1XMMx/zIpGVMlbJbqosN0GEFr1G\nmm31qNceaYJgE/bR892m6uUXon+uBdfpKDAyPIFmFdQYvwLeH8l8eJM1p706\nCHhp+PnQMTa+Fgies/Sp59QV3GVk5YnSCZ9avOMA1wwpqcSmxsnMT/d1M8C6\nGVOC6G3bXN8ZRKRaRgxrJ6R3MYbecxZ40dtClJOr3UnIjbp2eo5j0LDywsHF\n4LOw85IZ/4kEF8rkwUKdv8nKtLGVKMIL7JKu7+qtiqWvSTxxKp3ewkY4JNSx\nlPIO\r\n=uqLX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCy8hXe9vCGYp1TLDjacJ7pp/sKdBJrfHbsnwn2CR0PAQIhALgQz3xtaICTrvsa1FQsFSxxgd3i0UIqQPuzvnrWKI9f"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608185511.0_1608185542917_0.5627012624431882"},"_hasShrinkwrap":false},"0.3.1-insiders-1608281809.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608281809.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1608281809.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608281809.0","@vuedx/projectconfig":"0.3.3-insiders-1608281809.0","@vuedx/template-ast-types":"0.3.1-insiders-1608281809.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608281809.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608281809.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608281809.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-M5oLhxXZtQFcZFOP6NGZMY2n4j3ClL7zCwJJ/fSBzM8f1r3QpyQZVVldZ3qoZmU9EyFk2OQSJgLJ5axfwJLing==","shasum":"adc55cc90250ffb06f448d5c3236a02806477618","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608281809.0.tgz","fileCount":8,"unpackedSize":1217678,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf3G7vCRA9TVsSAnZWagAAT5IP/1oBifuSvhHRm6cMJQlk\n6kGprkGo1ElEcRVRIjRJxn5sAEtzWYWujzv8YEjpqWI7hrXWfDpRwKzrqmTQ\nx1bLjHLV/p7CEjZmbkA/Wt9m55ddwBnclUUPfbvKaWPhFwJTIvsomLIvoZ3E\n0xkOvWsAgwO+z4FT5B2ZtHM9lUikqDVDK8rG5JS8AUJh6F43fFY+/tkqqNhv\ntRR58tWJSDEmD2v2lJz37XpTA2NX0m0pV0aeP4dv69GuQmG0nKFoV2vvLGt7\nI+OHhZ/53uXht458UH6jCgS3e2garm3PcCLHmDx01CdSssmddpJcdUUHAY+/\nYILZEqTiXPbb5Xei8Q28tqD9ZzoWS18vL3jNFJ4hEiWFkdf2TSpGw+1aEeJF\n1WXEL3sxRneUzGp3Nrh0oRZXeQU3C+HHpGlq5nTUpSFTHxmS9PgFKdeF7A+t\noK7iw1RHEymt+R1WY+vMg7WEgXMCRC/nMOD/t4oa98M/Ia/rBuYTy2u2TybA\nmyAxBzcemQnknDuoVNmfokhQltzMLyBnlTug5/YzF1twWghrPQ8Hd9fUWS+u\nJTZkPUxX3qd1fPY3ZvrKkdUFwPo0XPJkoJ0xdaGTTUF9/bV+VIsSZHp3/o+O\nVYraczexoM2bMCMD0CAv7qYHIRbXHwDLz53XCd1jpeo5mylTV/6QRa82jQXd\n1PgD\r\n=XbHQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAFLplWkO00NkOqoxa9HgqL5fRxOcQ1DsUPRpG7AZ4YjAiAYwSGOQRxz5emXRANCGzS+hp6URdYsFFvqYwzQMaBh2A=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608281809.0_1608281838761_0.7543708347113565"},"_hasShrinkwrap":false},"0.3.1-insiders-1608285835.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608285835.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1608285835.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608285835.0","@vuedx/projectconfig":"0.3.3-insiders-1608285835.0","@vuedx/template-ast-types":"0.3.1-insiders-1608285835.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608285835.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608285835.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608285835.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-pvFGK08KxMlvWnMrFkdThMSgeyUhmBudmiRRbqKm82QcYE9LLQWujfCQ2mm2WDORIT6xVEOfHjRXxvQxT1UvCQ==","shasum":"76ddf6c4259e542fa68f85e9a99db8e29c05ec94","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608285835.0.tgz","fileCount":8,"unpackedSize":1217682,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf3H6sCRA9TVsSAnZWagAA8eMP/RipfxYUjT+Cs6IzM58n\nsidO5vbOEZN57Ad71bMnDSobtGO82FpH5eUiPCQ43/Izdsha5bjPSfD34Lt2\nsjw6A6tbpkjVY+Kynvr12g3H1qkhVEBPdYGxkg4OxL3DlREJDUWC72hmGu0w\nbM3i949iZLjoTqX5TAkDgiQSqDU03bQGiUgLc0kctCs/x8FklgI5+gliMArn\n7iZaF39WFT2Vfnn/fHriqJbMHfKfP6j6EpJM1r/JGmkxlxS8WyJ1M2Y4IH+d\nbvL+O1MGaIpNuN6qSONrd6f7BVoGRXa2HEHxM1IPLdwDCyobFw1gBoHWETz2\nWe4ETitU3lNe4x5wNZr72uJ/iYmmGw+K56Ha1eJQJXdMJ5nYsEp/bLyop/Vw\ndEaQgI6wV3cRKUduX/ehKPQ5AlZZABm0iJsKRTgAcLN1FQmHv2Q/MCkud2Q8\nUBbazlgkrECYx0fxCsOA9ViMrF2i8l4fq2PgfCrDEFf98/ViiTN1bX0/V/o4\nfdPtWGMHkIpX853aIQ2gUwqUjntJqiK6kUHBHjwfPsehALV87+j2YYO2Iv4J\nxqPaznne+mUid4v7z8xiX2uvuwE1qUPYYt36PlxpheBov8Ic83dxQWom3SWj\n/23w7j2JF9dk0JGCBiOseAh9cxSsKTFhqAqoxJc8fWY6LREiwqRMciprSZsS\ntoEt\r\n=uDBG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDwe3PWWfzidNHnLrfUe2ozXTuO8shBhgKJ3rTAFnzY+QIgfqrzviBds9oV3S0o+SN6RVSqo71q1u3qZAKzVu/Zj7g="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608285835.0_1608285867970_0.1760004369182404"},"_hasShrinkwrap":false},"0.3.1-insiders-1608294809.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608294809.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1608294809.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608294809.0","@vuedx/projectconfig":"0.3.3-insiders-1608294809.0","@vuedx/template-ast-types":"0.3.1-insiders-1608294809.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608294809.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608294809.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608294809.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-DBdSCZgCdVIXPTh1i8aGh6f4igv2clBNO96Qgb1kloW80kumugNIY/wutnlxo0+ZZomObCTEuYXvZYHFh9JH1Q==","shasum":"3e0c035d06c1aed1bf293c54029e0d197572a521","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608294809.0.tgz","fileCount":8,"unpackedSize":1217946,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf3KG2CRA9TVsSAnZWagAAiX8P/2ar8OQRnT9PnU4HSQtK\nPhEHxpxcWxlUvMxC7o+DMliYYtQiswvqwCA2+v96qCJSyW+JxsZTA97+qUe7\nYQuGoUKdPxQlukujVvfXfwgwU2ZN9Qr1mwov2XkTt5NEBkMQwT79nx4f86JA\nRjhZI9yCkWGT3EcVsEKBhbmHv9kMqibIxCUo6KpsePHnT7NATrfg8vLvuTzI\nhKZNmtiEk3UzLm8qfo5LjXcm5MljxXFKmoUwITPdtY+5ACmBbOopoRvWpTL7\nxv9sCK+b/UWaRrLNyuu9bxe42+h/L6nyBpdyesbVoe0kmsrAQPLkVlco0caa\nvpMnIcpoQCMIi+xztOkonFaWIaw8roMptU0AkVsejgvxeYkXkMEm/+O4Mw4y\nrHRCnupqTSPRUbmNBUsY998qRM2bQY2WCk7qc8Y9qMhiPIxka3Vbwvc0N+Fg\n3QkUr+QzyBtN4Vr1po+4ekMkqZXAyI/73i+fqfXIDrh955CNLf91tKLC9Cvz\n3s3UfFl0MsSDi7GVg3YW+UwZn6Ff0OuqZnGO4UDEedO4ceenYt7fwB0LTIyP\nIf1rq3WZcpoCiW0SIFm6+DfTxtYxqkZQhqLk1kQUKQMOKJj+zH8RqUERsbFb\nzR6AzSf+OFcLTRU+/tJ2sR9UqSWhEarSnQe3IJBOEtgCoHZst4RtZFWh9jJx\nNsvo\r\n=PaFA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDl+Evuxy3Ci5ppupF6teaGNbtj5EBvdq68iYCGcl2ZKAIhAL0vUOdQ3KwN/3wPuNSDQ0FpENK1gA/1Vv5t1dhBF+ws"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608294809.0_1608294838336_0.39263508595706176"},"_hasShrinkwrap":false},"0.3.1-insiders-1608632613.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608632613.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/analyze":"0.3.1-insiders-1608632613.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608632613.0","@vuedx/projectconfig":"0.3.3-insiders-1608632613.0","@vuedx/template-ast-types":"0.3.1-insiders-1608632613.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608632613.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608632613.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608632613.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-qqJGHR1nQ+dBXCpLc6RyE/nh4NqNnWSy2psZ49jnIWpb3BWbkaTD6DJJrEtVbMMgPy0YvhilBLoiOOdttjdpiQ==","shasum":"38e5c20927171e6ea5a318221a39bf3276c5f459","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608632613.0.tgz","fileCount":8,"unpackedSize":1248171,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4clECRA9TVsSAnZWagAA10UP/16RiuejL0n/pamJq6Qd\naG/8q6im+OEr7166du/hNLJrP3UQ2QE7AQzAwmRWa3XlmGt5QvcnrN31W8sd\nyOgA1I2HrJzNiZv4s4vM0dX0TJUrP/1cwKnESciWAYugl6a3LoWhbuQi9TBl\nZCRmLCUr1SOXcYGxOj49/giYEVIQ0vV+LG51ImKAg95BmUFOrnIXCZNaz77c\nGG9MYl39F4ql7StriWTBRnFYKfhVY7IlXe1fNsGf49ggWr/yT74SFfhkb2Ju\nfPjfpRGVwwy8znZjq3bEByn2/PbmGzbiG5AmINPQ9F2B5Tz2HLQs5B8zT8Rh\n0CNEg7Kv4X4HVRfyHPE/fUd0XZgia7I1+R6PNeAFI2spH0orF3aFHNBKyJM3\nScrV77abBBxDOZ6avm3GJGbFdWF7E+AhH/v09VSq31tWag7VaT9MISvwjYst\n4F5iqtXoXBlUbL8nD4fPGeowUbiNzVrL3tcW/yVVOyLm1jYWxvIU15+iZtmU\nZF9w5mitTuaALb672fxL1Ebw+k4si/mUY+JSYoJC9mnHQqi1eB8RXSQxwgBa\n21YPuE3eNa9D4A3qD1QQYr8m3ufGTGaGfjcfhbfW34iWU2TnX7HZempa5n7d\n9Jj4FMWQ29RA402+GMRuRBn33eRDqZdS4tQvwH/J2ZMYaFaxklWREK5OIc32\nxF0z\r\n=6QE8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDlr9238YrZ2gDtsSsNXGyBWl1uBjMxAD2K/sM03vEk3wIgL5NsDjqHXbyalFOmv0R6wD1prTre8znTfvU9nKb34A0="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608632613.0_1608632644408_0.4553746198084929"},"_hasShrinkwrap":false},"0.3.1-insiders-1608642006.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608642006.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.3.1-insiders-1608642006.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608642006.0","@vuedx/projectconfig":"0.3.3-insiders-1608642006.0","@vuedx/template-ast-types":"0.3.1-insiders-1608642006.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608642006.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608642006.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608642006.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-uKs3wpwYOCyLKx9a6x90y4Qv6zigtoipzoM1vGsGY4p6YNpgAD6dPKyByfrLvJ/rxdWQFy2L50+KHjjQ07KtCw==","shasum":"6220de5fbd48ed3da1ffaacda15d63c4ad00ba82","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608642006.0.tgz","fileCount":8,"unpackedSize":1282808,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4e30CRA9TVsSAnZWagAA4v0P/2Kt6qyP647KkzQEs71o\n8924Jm5P4JRx9QVNQ6lpQzbX5ctoBvIyxkOvbq8AC3UbO+4Hl9pjwovj6vV/\nhHux4Wlm5F8m3Ods555bW7/MmFY7csHth8XvbxtfomxQ4VvMdEF+ul4deTsD\n5vYkCcTzPpHEEE8nFvrey3mvvhFuuoIenUhoXAaILiwxtUqUc//sj7/SE7GF\nnUS+Jo6liEasBna6LhUkduNosgFp7MIco7L45N7wSB/rjqgPAFWxAMUQq+xq\nZqLVgs50A/5EBE4fouDZR5uDJ/gzj2UVOtiQj5JeWMMcWmNJVoK7ksPqHU2j\nM3JfjTPv0zaYXnf/+sOAMgp7e2ZeiqzgWuIfWln5PCgk85NWSfpoIJ35X7xG\nnsIRxaBKYxy7ttEYRVaCI10D2uN4GTrs5ETMSttaJxMUlQhpQsfGP0skHp2W\n0djyuna9QLElOiEfQYE4n9dgF+ePsi7nRVSqsYgnTj5VctLYUJjyIdAq4AzD\nlIIATs4ryij9yHQzRiQLwA0TTF0g2dhZUytvu38XYMVFCrOaQGz1unmeauxR\nQ+m5xcJT4qE99mg78FsUXjuWUQUgwopfzb/9KaRjEGumZaN9EY8X09WRaZrc\nqcyQSYAvV8xUp2Y3nNY4pKXROGVYICEvwvB3UH4s3uytMRvwz8FalAU4SauF\nS3Ey\r\n=t4kq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGKdwy7oZ4kOHFS6ZW4v4fCphqodPDaYbPUDxdJoANNdAiA22hEUzDWHt0Q4hzBWh2Ud1v/EP7DL2P175SRQPZJdGA=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608642006.0_1608642035679_0.8118407823947302"},"_hasShrinkwrap":false},"0.3.1-insiders-1608679071.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608679071.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.3.1-insiders-1608679071.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608679071.0","@vuedx/projectconfig":"0.3.3-insiders-1608679071.0","@vuedx/template-ast-types":"0.3.1-insiders-1608679071.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608679071.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608679071.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608679071.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-TG9xInYSh3e3vDyg7sADoLOlJ0fZkcLh6f75JtEYcxqdKsVpGzoEhUr2CKotNVC/j7JYqaeRhReZ6N7S5jUB9w==","shasum":"15023bee10335ca208cdcaf233c8fff06c533d31","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608679071.0.tgz","fileCount":8,"unpackedSize":1282808,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4n6+CRA9TVsSAnZWagAAtwkP/2YNJbnz2fpkDkzHZkng\no2E1ugV+EsXfH272TW6lnaAn/Flksdqs7Ws31QT83Xoz40tqmCF/CV1HVf+D\ndKH5zjFo3wGD5VUvZsad13xan899DY0Pd18IGE3X8eewreSJIIRdABe664SK\nF/PaeNJJj3A9o3hHkWEkLtuu2EkbK+38mvizVwXB3tmoBKPD/QQCeVUVFFfn\nt/PoXXkCagaof3G0V8zEawLbnM2KGadD/mue4m0q/rKK2xWQ7SrXyzRbqTh4\nziv2pEyH0d3kjgN6ImU0UGsX+ujWyTwUVx4k4sHbEPvdc7h7NhwYF2VzDWrZ\nfByePHw+lq5FzNafNzbSpIqBVyWfw6x48a28Y5FPfh1S9nROwjbxcmKM4FCJ\nslLfFKguAl2ZgakcSp+nlC5IX3uvPzf8GWL+DVoiDgt4hqV5gPoM7J1Mitdm\nzBvXkdg7tvpzHbjZid479zWDMoyj7i9G1A1c83zLo51hP7dGtujrgSu0l1NX\nvfwP6DIiRaw0ViJwj1S5XBZH2F0Leyj3+x7ezuLPP3jTOSFC27dFOQ//VHTF\nXltsTH5LbWnx1NZ3t+7kNP8hzYrk4vUEtRpJvWH1TtCEde+9qzL1MjeDYmYK\nkhuKE7VcduNkqGSySfYzDLF5jKZRWpHtCHo+WBe6qgO4gz/4fKwTBEq1bjG5\nMquZ\r\n=4MN6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA2wRpFgzJajSthzOHCnN6ZLoQ2rLlZH02wJru193mIcAiEAgrvMq32E8j7vLW25vxRmFvH94qCTsgHnMXmyaQtf2Oc="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608679071.0_1608679101694_0.04383391438829709"},"_hasShrinkwrap":false},"0.3.1-insiders-1608679989.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608679989.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.3.1-insiders-1608679989.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608679989.0","@vuedx/projectconfig":"0.3.3-insiders-1608679989.0","@vuedx/template-ast-types":"0.3.1-insiders-1608679989.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608679989.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608679989.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608679989.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-+Y3nGbBoWAST8HF73Rrf0GB2QWd1NZAz94pIYF3H4nHay7BT8Qll3NwMJ/IGLb2lAy8dsjb3KPZJZj0xG6AcTQ==","shasum":"ae34052b7fe57578dda321bd453d766782cc53e5","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608679989.0.tgz","fileCount":8,"unpackedSize":1299862,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4oJXCRA9TVsSAnZWagAA00kP/RmHjvX4cw0r+dab2saP\nvFMcx4tQQXYJOMg/24rNMtEuvbl69bE17sqj0bkbYk+2Votjx71Jao0l5qEz\nB6qcCsmfbN0rda3VBaX6aMAT4nwrsm9KJttRa1Lg/5eyvsz87BtCWYGkkbcy\nbunKeLDcQoo3lr9oY1y7ir771TKJUCdaCmMAsVkhZohpWSb0Uh33u8p37GUW\nVHfzZarW5s7Yb4I1lEkuxsT0h7E5hAjG4MATrvzPBNUfXGjuDeoFAPNnee72\nQfCGpdAOOCFtV6VJakoXse+v43bwYHY+oixbNDbjv7lM7YpbA8U7vo2PNyy0\n1R9gZgFKjaK2g6/84n4yNDt6c3U8/WvQp8+GMm7vCZZFabeW+Mqf+29w52HI\n/6HnoSigJGQUu3diov/zntHBFx3RC/ZvA/akkGQy2Z9zacrPVcpr7HxiBdB0\nqNyMkyjmvy/5NefIMd6TkWQ2wWUuYxRDgWGtwBHkv5VryQ4B+COEldkEOtcH\nknXL/+c9JAeESy6pBI/Mu6dwflSn8+I5UpdBQbQpE+jvTnA8SlCMcQKQjphs\njly5bPtiaUwt71SvYZ8jVLk3zKGSN18V8n3ovC86a1WasGbk0f8i3BjiB9NH\nbHQwdm0sI4ovkfk45433ceXeMIxQqUS9kAVEQOkp0r+MXThE9YcVxnlFtPq5\nMe/m\r\n=HyIl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHJWyh5pqdDXPyM5luuwUmyPWHGVt8I+uMBP3HSnwhGoAiBqmzvWo99Bdyw/FS8HfEqyXXwLBjB30+LEx0wqV/JrSw=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608679989.0_1608680023446_0.056667754819096805"},"_hasShrinkwrap":false},"0.3.1-insiders-1608682132.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1608682132.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.3.1-insiders-1608682132.0","@vuedx/compiler-sfc":"0.3.1-insiders-1608682132.0","@vuedx/projectconfig":"0.3.3-insiders-1608682132.0","@vuedx/template-ast-types":"0.3.1-insiders-1608682132.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1608682132.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1608682132.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1608682132.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-4FSLWhCn5+DQ9mrfTvq6/WW+WP2kiBbqhTNo2E8rDU5TVtFq6EBlhaT7/MxyK7XSE4/o9iXqYJabaZCMfdeP+Q==","shasum":"5de44348b8e4353ff72cf1eb8488aa69e9016039","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1608682132.0.tgz","fileCount":8,"unpackedSize":1299862,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4oq1CRA9TVsSAnZWagAAhFwQAJ6QTH50r+C96pIIeON0\nZFyT2+AxSt/MiWsfoKJ/hB6RtSNf1ieOfywF7aeILe33oaLiw1l73jXNtLP5\nQ31dKkzqZeLKFU1BN71y3J1b7Hmb8zsfOxRWU57NjxlnoMFwdEqLqhtdx7Bw\nDg9jm7+beVbdn0f/vU+yAVfCzDgdldZH95WBLUshc67nu/Mcfy0WKmj5vOEb\nHGU8hKxY/nssTbin1PSIwvG0KJ2rsJR2/9bQVM2GsYap+oc2MrQhVb8aus4P\nEYVcTbtv9FPcicC06ds3KPioLMiMErxxOENWospWIvudZR0rttTKLYNUfuMF\nISaFpllsnF75IjlB+07owQ91GSJTpBGnquk/4WqElRFzH7XF8rQkmGa0Qw0F\n/rB046Wk6G9vmSSxRtXRav/33BFkaRYt6hwc6LSvUfucUOF/C22QNgFY9CL3\nyBxiLL5Ac73Z4ks9yRhA2fZ6jlavUx6q1ZuQtIw6ENGq5bSdNzXDSlfsC2/V\nXuGQfYoaS/MWhXQFxjg4Cv9W5pcO952pxQrKyo0qSRqpO4105BLNAerF+HIr\nKKqKTd1coTqD3KLUToM/yWdNWzKAvfdcZs5esUnIdgiGvRuIcJBjk978SZvF\n0WmZ9dPvH+UgsRJNkd16ogBmSBF8Y9ksv9lJ3ugBKa760Fk9/XWxnE6t7Qby\n7rcG\r\n=MycK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCBN/2Qp+TORs3ca62ZPN2uX8yesjIXuOZqpTT3mHoM8gIgHlOQurIoEKenV+9T3yEhe3LEMkAR8+RyNKEkywBGCXk="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1608682132.0_1608682165325_0.27314852506782494"},"_hasShrinkwrap":false},"0.3.1-insiders-1609032938.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1609032938.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.3.1-insiders-1609032938.0","@vuedx/compiler-sfc":"0.3.1-insiders-1609032938.0","@vuedx/projectconfig":"0.3.3-insiders-1609032938.0","@vuedx/template-ast-types":"0.3.1-insiders-1609032938.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1609032938.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1609032938.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1609032938.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-gxAuPCYu1phvyBJevZSHcXMgFvE57Sl6gVA4bcvrpsexnqdkUJtTuI0OCbn7HoP+CvHGoQVDQtLQ9G1DR0ZyNQ==","shasum":"2022302948d21da23c21f4e529a22d01fb156853","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1609032938.0.tgz","fileCount":8,"unpackedSize":2000126,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5+UHCRA9TVsSAnZWagAACn0P/iBcgtxiy8zWODzRHXwR\nfGSYjPQ26K4xW/+iqqlPo1PLinIS+9Wu/8vxOzbff/CJbO7NS2a7mSTphgoZ\nWP4YD65KizJYqVLAbRzSqUO0VrQPXaaOf23iDI6ugzl0u5NklsXybXitiTmN\nnoFeZfJ5E6k8FB2bYUEet5ynJSWrQ7LFItLxmzyD7l8NmhJi/HxPci67NOe0\n9HOvxSkOR+s9odlW868VnkZZ3yg7WQrGy8VuVgnc6y6qh8nDdNjnZtOLcC/p\nOT4wMFtGjXxO5gVS3kHsua2EpcwA2kCVo3ct5VI8iI9lSxRX8rrR/eiQKs0Y\nW1XFErxgKJYxpgwHSMAML91AyXjaMgwLheO+MXZYxJm/i0xSqMBb8nYuKHYf\nrJf0Keail0ZEd0idGyspjw3fkjHFcjXpAr4A73xJm//pEYtulAmRFv8U3O6q\ngvmZis9oUdjyyC51x8R6bgyrAm/dwX0y8JTAUbiNK2Od/AK6uh37JZazJcIt\nowMjYfIRj1wuIrYNCU2k6/RwAk02LQwTIoaaGDlCPo6rzzmxxl9GrZzZ2q+7\no39L4RnLvAxeU3lUrQOZvVymPjxSOSBvJTTf+XFfhJD8Y/ERMiOnkFvdsXBM\nNCW8tlYPc1Rue5AafW2nr8PVGtjRVr4VhYZOLCR7ZP07Ka9GpVIT0cLbt6Zx\nXnGR\r\n=SjtM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC49GfNAiK/Y1rOJpXCQwV9IXV/6EWRm2wDD8JMCdTWtQIgYi+5yE7M/FDpkQ94ogbOUc9qIV1RNne1Kz7zd3gQs3A="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1609032938.0_1609032967384_0.6470159517777274"},"_hasShrinkwrap":false},"0.3.1-insiders-1609034385.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1609034385.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.3.1-insiders-1609034385.0","@vuedx/compiler-sfc":"0.3.1-insiders-1609034385.0","@vuedx/projectconfig":"0.3.3-insiders-1609034385.0","@vuedx/template-ast-types":"0.3.1-insiders-1609034385.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1609034385.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1609034385.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1609034385.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-azuqyOHVE/seiA3cbI6VM3bVhD6FrRA47L3KuRjPvh/2yC4vOoh5uP7FtwyfGPB+/GqMWztMmMT8xoAY0z3Ceg==","shasum":"7c102d3b10cce3e231a741753ef9f2d402963426","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1609034385.0.tgz","fileCount":8,"unpackedSize":2000322,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5+quCRA9TVsSAnZWagAAlS0QAKTSvI1XLlhDyxl9m0Cn\nasE19J4VVLh3FVfLfBxIVNsMAx2odU5bN4GyeyxK7M+6/5gkuDy2YJG0pZho\n1Pgj+au4NZ1qOHJ09UPZ8CdZV7vtEFbOLeadn82Nuq0N06JPdNBR/spwD80l\nIfORydpQwKVgQPaUbpd34+i0qZByWOSt9TaGVq3j6GUy5e5PrdORdQ7oMPvO\nd2b3JkBUweMMNyh2dCbuYulic9Mndo6qYu88k3nEyqc32TCaLWLGwFSlCxck\nOV/b9YtqlZqZMmFmlG4NOFYdHEOhxkoq/DwYKr/4dJiyxBLhCzEZvzURxGbh\nz7GTyhC7sjyl7QzKLxOq1W+RAIkRDzBPGA2LMxzLeriNvvJT/4Jbs1/ORXyz\nRK0/TnJH1ck0KAOPMAs+rX0gbnMUGqTdVVXDE9ux35NbCeZvH0pe+CwCHtDf\nSZVxdY9mBKDO6VQCNUP2VhEMn+2HsReqi2qRkBH8ojXaQv9himwdgEBYS1kd\nvJIfU0WpOskqQFjpWtY89e4MCFVAhyfLcs/WAKqWn7BZilYLr15vdwQIiJhO\nBdjFn54M9/nOjToE7zQZFEYrwZoWd2nplwqnhSSkbgx5FMMgyZ/ghL/PXN0O\n61ql9/NNzK4xJykqjjTdt8iCEmisasByrS5/eRrNWLhh+/kWDgbqtylO8BlM\nALcK\r\n=m6od\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDnu2biRvuJ7yqA2b43L7Vm5T6wQIAtiz4fHnRyhALv9gIhAK5KfQgc75Hcc+ygB7H2Qvf2+BTmS2rLnFpBDq5Mp1FB"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1609034385.0_1609034414440_0.7177735778474998"},"_hasShrinkwrap":false},"0.3.1-insiders-1609155664.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.3.1-insiders-1609155664.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.3.1-insiders-1609155664.0","@vuedx/compiler-sfc":"0.3.1-insiders-1609155664.0","@vuedx/projectconfig":"0.3.3-insiders-1609155664.0","@vuedx/template-ast-types":"0.3.1-insiders-1609155664.0","@vuedx/vue-virtual-textdocument":"0.3.1-insiders-1609155664.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vuedx/shared":"0.0.1-insiders-1609155664.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.3.1-insiders-1609155664.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-PGsOtaJMoMEkf05ZWn8A/XB1khIdcqiGN/A/OlffJr1XDPIcBixxcWkSz4gbp5GAPRBwqRJi3LZmR2Sp2GI2TQ==","shasum":"8867dbb50070cb0f5534cbdff54c8b6efb0415a5","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.3.1-insiders-1609155664.0.tgz","fileCount":8,"unpackedSize":2011882,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf6cRsCRA9TVsSAnZWagAARe4P/0VCR7Yz+YQmdz7NiSjg\n39J65E1iOErimayDh4u1qYnog8B4b54gxtqS2EOgNERz1ym/7qehN8XBnfxG\nuUZpeL7hJBLYMj7WSi2uRK5a5NwZ5u64U/Mb8nOad7YPa0+jsLsM2V1x07VK\np+dGKyR2pmr0nYcSWnIQB5e8A7/RwpjYh3pTDtBh3ZnhlxoJjliEgt5EVbuF\nm89TPUIDd3zY+bSlNNtv+WihaEqvJCWmidCI6Gb+tk6jNvRVSrCBJU0R08HX\n7lKtHkqnHqyQD879UXG/R0yCzn3daqU39aGGo3fXqFdyhrpmCIAMErUPFbPS\n44D5Io/2Z6z/B0NqUxYuUwKxiQ+j6f6LzMZ/gp0kDxTcrVL6ix7nUebEl8Jx\ntx/nFkazKNbk9710N/5ZBdfPuHUUmT4p36dJbgp+gydjSBj04u6wqqFw4ex4\nc8T/jiiSpyhXSC7lEcC8qD49HgWpU4Qd+Q6hQWHVSRvXDGSYkwKLtVnKjKZ6\nreTF8s7XMR6za/ipPxfyCShsSSPZA7pjRB1nWflgcr9cyH+MjOzYbEsj2ty7\nfrFuy/Esr9dk2Q0rgVlZqh4lfDmdft05DeXjwbsArSyq2Fw5GetV2UyQbmU5\ntCClEOXR2L4XhPSSnJsXh3/DS/rXDZbFMjXe20ZuAm9j2Kl3WJr0g6bYBcNw\nulp2\r\n=KqLl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDISJyj0/KJWjIjPqh9sTpG0g3LGGhVXgsy69VwlADbPAiEAwAe9DMvgIm2KB/HkZafeZu1LqIZOLF5vElv44JO8Djk="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.3.1-insiders-1609155664.0_1609155692133_0.014878755142613054"},"_hasShrinkwrap":false},"0.4.1-insiders-1609180156.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.1-insiders-1609180156.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.1-insiders-1609180156.0","@vuedx/compiler-sfc":"0.4.1-insiders-1609180156.0","@vuedx/projectconfig":"0.4.1-insiders-1609180156.0","@vuedx/template-ast-types":"0.4.1-insiders-1609180156.0","@vuedx/vue-virtual-textdocument":"0.4.1-insiders-1609180156.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.1-insiders-1609180156.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.1-insiders-1609180156.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-MBhkS+MvMfl3U4cX7bi20tI9PhL/p/c0yUY0mOZlmZzzIgKNZjwWAQKyzXUTyMj5ciZThR5TiGj9QHJH0D2EVQ==","shasum":"f145d93bd398ec0beceba4125a4c0b888c137c7e","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.1-insiders-1609180156.0.tgz","fileCount":9,"unpackedSize":2550389,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf6iQfCRA9TVsSAnZWagAAsZEP/2tAOOBJl2D3Vuy9M7bd\nCNg7zjrAnoVdjDoils1QE6oum3EjqmPvez8GfhIdJ6gB+xCXB4luetMJMT9c\n3tOCWhYnUP1w1umJrSxpRmw6bWUzSUonWU9NPMpooItUP6/+v0B3maUl3Ct3\nM5ANvuGZJDxv7x6xZAlzhnThKtdAedzKWVgyllGnhQV1yFlcXtHgJ2jrMpmM\n0aEsg1LE0uZgDXA+eEbx9MQ8V0dxgJCYTpPh2H4ND5+TeJ3cuSo/0M+1LyMO\nQMSYSm+qh/ulwvLuSxv34oRk7+P5Zu+b/eejTpZn69gkFmZoHMzURa71YD+p\nxYpG+zo/aomfhheTrju5zzUoP33LGrxrtrjWFtrx2Jf4aXb6JcOdBM1nIA24\nL8ONR1qEitLIxdUEtA3Sl8nWXjXGu6xd/g29f86WOBHjNTJTpMQAsQL+X1m1\nb/oLgnsvxe7XHdGcXQ8DW/tt93LpSJpULKU5IzrRasSP8ZqA6jizn3gM3Liz\nTYgczOu5GXy7AdmRD3WeUmWUtezz3xIj5++JLGmiLqaF4/Z7M4VhCvr+++bc\nCTAVKm0j1OCqW93mbloIpZmQBIVg4wdtDYgsxUd0mnQSmQKmiuOqDbKYiHPW\nW20Teuk+fnpUvP++6x8kfp68wKTOhVtirQ/sP3X1Ldu+NP9Yg9C8hROY6Y7R\nN6W7\r\n=PVA2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF+E+1LuL+EqW1xeU6rHDiRDNQRDNvRZaiJ140ewQGLfAiEA+vOS4EJwgPzjaR3+w6tENtp38hwq+E8FxtiBTdPJlnM="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.1-insiders-1609180156.0_1609180191188_0.19810855530008675"},"_hasShrinkwrap":false},"0.4.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.0","@vuedx/compiler-sfc":"0.4.0","@vuedx/projectconfig":"0.4.0","@vuedx/template-ast-types":"0.4.0","@vuedx/vue-virtual-textdocument":"0.4.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.4.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-3VTo19ZhnqZbnu3RGRxDJmEw7KI4e+CvXGhrlrjTgqsxgS10yfqn44cgYXF7et4iv/5RRQJjFXUO6Uvla52e8g==","shasum":"4780912f5915e65adfcae4764229918366723ac9","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.0.tgz","fileCount":9,"unpackedSize":2550235,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf6iQ2CRA9TVsSAnZWagAA+AoP/24qzTBJEE89bx3QsLtZ\nXJOYNEkcBTKoNP9jwFQLxtkEV6EDiCWW7y+B/4fRj/L9xaAkmi66zKv5CZfW\nuOgm5LH81iikVzQ9HNjic9/zFTzAct976UutsqKaz9ij8vBvwe9oOi1D4Y+T\nfq4SDbewr+apS7Xq18W5UOxhn+a1mNvsmy+Csn0J3Nu8UTwsmSm7EApiu3x/\nYlPpSGcl4dtqrK/pdkJyd8q8Q5BbO8YMomPX0BufZWYCFyv2ByQ38YVnTZbj\n+zC0f2uKv+Ri9koJD9KvofO3P72a67cLx/rNXz9lUDrXxP5i5/4SABYtXlAG\nrUorbysy3aEb34DhozJe/zJAyjjxIYaQqvPcrRx9hOQnie/R3VaRoQTRbjpu\nJvv6ebP63QboD3NN+1CUujpUAxQI8udmnaqmcvFDU7MyINjAHJcXPV5y2P3c\n8hVd/tSMf4yS9k4rErZqEt6+0VEBad03+lP6osDLboDdK8WGl6hqPM4lg7e4\noxEAXH57Somwv+JDgd/SeuPvji66jw7cc7gAsWYmtfLfwljuD+37U0wgFHtY\n5e4JzCo298iu7ticblwQEBVPuGkClWILK6SWG/LeIzx1slFEtboef5skXYy8\nJQL26LTpbrZdS8SzM+GuI8IlhI1V6PAlmUZ5KGkK5O1dUyt8jJcATdmhRn0G\nGX3z\r\n=aBks\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEDurQt0RnOGUN4dGbZcLnYbAmQknIjufVxBJo7BZiUIAiEA0p0Wt9XnRHvNaEI/MTDKyWnG7YQmSE7E8Fy+aE2rFsI="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.0_1609180213990_0.023480546968471572"},"_hasShrinkwrap":false},"0.4.1-insiders-1609336775.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.1-insiders-1609336775.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.1-insiders-1609336775.0","@vuedx/compiler-sfc":"0.4.1-insiders-1609336775.0","@vuedx/projectconfig":"0.4.1-insiders-1609336775.0","@vuedx/template-ast-types":"0.4.1-insiders-1609336775.0","@vuedx/vue-virtual-textdocument":"0.4.1-insiders-1609336775.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.1-insiders-1609336775.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.1-insiders-1609336775.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-cpv0JhllS5FLK3CmjfrGmSDU78CNxHcDYW1DRY1fNRSnN4Xw2udq9b5uOOU6d2pZbjW9XuyQpUCyapzEH5krXw==","shasum":"7e1ee69ee705ca9f2a99a4c07e748534ad05d841","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.1-insiders-1609336775.0.tgz","fileCount":9,"unpackedSize":2550389,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7IfqCRA9TVsSAnZWagAAi2IP/3jsOzoNFb225DseOsg8\n89eJHjqeoWtD7R0LmuVRnH2UyMs8KMmt841Wlf37i/N35MeSllJaL8BofbyH\n0owid6ADGN0CM6Ps3oWgKB8bddev0SWQdr84dte32YHQYUDpSL3umMrN0LUO\nLmBk7SugTYLrmFD1pOb0L7v1KHGhP/HzbZ4qzN5YqK+tYDf3v35PB2nP1xMe\n5zXEeb4ksnPDZmx6v7BY/rjkpIw2DXgCBJW4HfwmQVxGK+Y8tR7fTuc+KVjn\nT/OTNDmd6mwCY5zdUF857CKtSwmg7EoUAWKiiaKOdCCWr34OUPdY44xV+QqG\nSXq+t8jiJa4KWaOzahe9p6be8kk/jNFjzO8SOK1q6HgTQqNke1+uKY8QE/qv\nc3yIkMdU+e2bq5yb94UqPgaW6MZaQ+AsdcSMtP5SgoP93lodAxVtH/vfksND\no0/khiV0dhpfe9bzLxTLQoN0f0TwL5PJWCNeY3BGjr9kcAyRxPBxWyMCNmMU\nTacdh4lFTJPWXLZTGeMY07u2Y6g0U23xWs80fxUsJQg4ztsE3usVoLSNccGk\n+9AD/8U5EVZDqmUlTow55ZV5BvFtzUGB85JSlKtWJvFQ9ibW8OPp7QklkeeL\nDTwwzkVONGIiU+YH0nbbo5WLXQOaE2BFADmFg0utQlMd8m+vbljsrENq8+i6\nf2st\r\n=xPf5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDEoqajp9Wm8zcLV84PxtzpjZeGVTdSqL4hwtWTGn4Z4gIgUgXUVRJcOATECfBCz3yya+E1TR/CmvsyEU/3QRr5B1U="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.1-insiders-1609336775.0_1609336810169_0.21730369161717822"},"_hasShrinkwrap":false},"0.4.1":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.1","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.1","@vuedx/compiler-sfc":"0.4.1","@vuedx/projectconfig":"0.4.1","@vuedx/template-ast-types":"0.4.1","@vuedx/vue-virtual-textdocument":"0.4.1","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.1","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.4.1","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-JK2PJc05u1/PfHd3QJ9jmPBzbqBsORzliglt8Xpd/wsV9pfRsIF/Qtg5bRkqc495MpiSZiyTgLFOxov216P3TA==","shasum":"5375ff9e25e1708d24a50b36bbb566a5fc82143f","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.1.tgz","fileCount":9,"unpackedSize":2550235,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7IhLCRA9TVsSAnZWagAApuAP/0F0WHHm/SEWrQYFkIuH\nOib0XWQoxnhpBu2hxhOIfLA0V/7Ud9Dz24wSDZ4H2CyCAk/RjQ15ahXPXOe3\nFtYI9D6dF7n9dTaPiPDaD5+ECEuGFVLoBvKrXPB2Lkhr7+JMyhCLBzAUBSkv\n+re4Vn6KZcCRgSxHtak1yO+oZUn5F9ntvIv2sxzL4IDICUnYlVN+tcVQtnww\nQNNIr3vPx695SLuvnuuVQpdRAFRdpE20Lw68OINtBZGXTl//GOPRzhXxksFd\n0f3X6VVaZWNcNotNvnIN8N66PlFOLtp/moz1C/R8ZJ4XQF8Q0pAQRP+3V+GJ\nxxKQKHVDCPLO/BWjnuQnkhOdQfNpRoPd8nTvOvhlboJ+S68Uj8HspU7/poEA\nnd7YWKh0LJ6GiSl0WBtOzQELgOYv6pLi/VxRk08u37oh8GGrd+5B9eM4K69o\nHQLzZyWffZEcmKCngw4tU5FvQyw3/X2cbwdvoltzHIWgDnDyJABd/6DM4Dqm\nZTtxsAmHRSpG5x2ukhX1AM25W1r0HTS36aLbwIVbsqUQqbJt2ad0bq+WEqmi\nzfvBIAtmlqCyphdxkwA3DoBLB5MxpT8TdFCRH/zhwO0On73Np5HmK5ImY6iB\nTHOrf1Hs3ToIQzja4ip2DZt5Ec4/hYrxEO2BtyY/WrnSW/g/HwwE0u2u3FFL\nJUQf\r\n=mJIt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDv5whi2V8uFKyFaBPBQj9Du73VAokRvQvv7B0paNiE3wIgQPa2weJsTSqAWO1bh94Rlhj0whj19pGQ2rXUBDTTWag="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.1_1609336906552_0.13709865026195045"},"_hasShrinkwrap":false},"0.4.2-insiders-1609376449.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1609376449.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1609376449.0","@vuedx/compiler-sfc":"0.4.2-insiders-1609376449.0","@vuedx/projectconfig":"0.4.2-insiders-1609376449.0","@vuedx/template-ast-types":"0.4.2-insiders-1609376449.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1609376449.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1609376449.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1609376449.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-EeNOtCSmdp3SjIGAz7Vb5tps5FwFUOsutpOg2zPz9SxZJ2AlfgPTbT/JsFkh90bqSsidNoxHYyaPrivDGS1wdA==","shasum":"8387b2e5b90504502b2309f328e7b31338c73ce9","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1609376449.0.tgz","fileCount":9,"unpackedSize":2550389,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7SLkCRA9TVsSAnZWagAAI0YP/iG9luQrRXIgNjn/XTIX\n8l23UQRPQ5Jxs3EUYYmtLB+weWSG731H36FcyCEwUVnxRd37nO5u7BtgcZrF\nK0q2P6/6Uk1cAASS5J7pF5j4e1LR2NZJd4n2TjrrUpWicsoo8vfG7tGhSoV1\n5jqwxlFQISln3JP8QEB/oOd6FuM0sfdiqTZP1xxXRx18X9GrrvR4eSpaPqg2\nhWTIQaZzANmldHzmPHHAqukgPTMbHCZfIAmbden3PMtwYN9lVvyI3w6fGkDJ\nBl20kVpQesuJyxXpXWmR44SkqR/WOMUxiWom6Ur8Ji48Z+z/UPq57aSeLdx9\nju9xw8vloKgnAEQiHdv/fIrjx1m5S1HXf2f4u0mSqrAx/bK0KgfeYxsaRJOs\n62+vgQNA4HyOvKughOU9SZoHxEZPMPyqHOA5ywuNEgktyfQ8cDDy2BC8xqEt\n++oQAnfC+0BHWoItWJj5X+tC0jeWlPVXFQJbiemgAVJc/bg/D18yC51v8yjN\nCI1qrd8Vqtng4R01GVw5vjSM9GWjWULzWA2jo59TFUbOwCcI4vWHWHDTZEbc\nA7DbGu3DyAaRSzd9nG52TJtrkbxaEeXXI44qmHl96d8R/ThN3PoaumJfL3pL\nhMvcHC/AZoRAZp1s+wEErJghjj/5jG4T5bE1nXz9wzOTq3ccxk6jeqyIl8qj\nTR5n\r\n=1F3J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC6wdoN7gWRXHI6sNgqRvhtRKtOcyZuc/qM5y2IZgUSEgIgYDWQpxrTAyc2Z7dsMWCkoRmHNYafIPTa2MPHwifmz4I="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1609376449.0_1609376483576_0.2757952957476544"},"_hasShrinkwrap":false},"0.4.2-insiders-1609376781.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1609376781.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1609376781.0","@vuedx/compiler-sfc":"0.4.2-insiders-1609376781.0","@vuedx/projectconfig":"0.4.2-insiders-1609376781.0","@vuedx/template-ast-types":"0.4.2-insiders-1609376781.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1609376781.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1609376781.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1609376781.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-IGbi5hcxjPUQbfxOXOJnA+vMHPzfL7TAPEWYnt00PBZQL0ZMnrEvvSvNUZIl46m7RjZ6Qndq0azSBt3qBYgneA==","shasum":"392f69c1eadde87c3b081f7a9ab2527f6b68746f","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1609376781.0.tgz","fileCount":9,"unpackedSize":2550389,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7SQuCRA9TVsSAnZWagAAEK8QAJBDo7ztlPqLbqloTZHs\nw7hAKWGdrPTTgZkoDSA9l1A4ZyAzOG7TnuRD35TQhHrkzeSPwh0feaWu74r2\nbCJ3lzRwOZl2SOQfsUKA8rE5cZZWT0zpDI7tbq/5RGchKpVTV0A50lb+mi3O\ndCNBYqaISDVb/HBagoU/MeNt3CJ3884m/fcbq41UkVmO8gWKF7NEI66hC6Pi\n5RtI+wzLtVbeQbbjkMGt/1Xnm/uv9hxKumn4vKc1mffe88LdgL2WRJmUFBWj\ns6FX2cysjaaLMRhY9L01TOHvGuwjCcxWnabOqekSU/7qvHt2S4dfKuZ9oxcQ\nPDlES6o4qDqC0EkCixtowS8MXqwykqtAtwu7gIRYl8ACjiqWI74YEqYTXPYp\n1OTKfCEtyQrIR5RIBoGeNu5uueaAR5qj2fJFxpfMh53VBd97qxx5eAGsvP4p\nyXpsJizkn/eActIOCeEjXirYvYS2SfwCa+4nygzoHF1x2BxmRwH9xaevH9eY\nFi6+6XRM6uBzFaiHsHeGgbwozevPLquUzpfszLgIfmT0H7pS3HowdhjwdhrG\nXalI6YYYyzBpPCcmcWiPWsgTn3xXi3RH2QYWTHesmK89PtrTFLNsteiz12wU\nLu6HD7SpRbcFlSgU7iXnA804FjBKOFEIQtdSBx3mT0msi+2fwejYQA1YzhyR\nvxid\r\n=zihg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG/ZEvscx1J7Lvp/LLE3+8NQ3mRlaem8h1YDap12xNgFAiBneg9xng4Y4Khe4gU+d5X/WAxNXcOWcUsrHGL938F12A=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1609376781.0_1609376814442_0.4199737811824642"},"_hasShrinkwrap":false},"0.4.2-insiders-1609385764.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1609385764.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1609385764.0","@vuedx/compiler-sfc":"0.4.2-insiders-1609385764.0","@vuedx/projectconfig":"0.4.2-insiders-1609385764.0","@vuedx/template-ast-types":"0.4.2-insiders-1609385764.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1609385764.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1609385764.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1609385764.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-qi/d6ID8jEpRlUISFAp875B4VBVrUTq/K1sp4BnK3j0eEeM+PVBPTW91KaAxV7L5/XuKzQTDXWMKJ17oLHxMHg==","shasum":"99989ae345aa52cb113b65cff442de3d2bfc3c6e","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1609385764.0.tgz","fileCount":9,"unpackedSize":2563744,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7UdUCRA9TVsSAnZWagAAbrMQAJ5moMDUS1v0DZgb1AvK\n/FINoUjosuMsWntxCfaA5rYI+oYz7HvvOaussdMIpnViHpL8tT4Bo03ssi6w\nJ9tPvVP62Na2Thm/9X6XgdVIAwAWAgTDRyDZx43reJfH46uQD3mt7NwTQ5r2\n0k9nttRs4j3fZVyr0Ps9EZUrEMAMVdDmWM+68vhEgWlOJXhdCKIdM29zVETv\nLG3vqdlh7SI/1RSBJjFlJB8nBxHuXFLtGHAaW7T10x0uOxdgf8RmYlABdShL\nrgxCkyC0oSgDgVsnaY0vEi9mDwzVKjTE21+EzmQ060wpxLD328LkU9YfVWnA\nHsPsWdVaevfLsOHidmiC0wHc2d3JPTLGDrV6A7kim1dXJEPUMfKzPCqaB8Af\nbSYiWiv5bGdYW2uihL3lfFdn2dnsQhgOAVfyvG4scFIw6MNO5W/hiQ9av9r0\n50DKdkEmC+teMGjaMwBZPMcUdAn88/zQvBha3ZuUg8N8HkYWd8SyYM89gF6b\nM5h3w3/Xsx2YI2lPyeuy11CSzlqqHYfTx+5pROkbIXBrFbV2NVymEdV9oulh\n5ISWPUahJuqcLl+IgJ2/S/VlitN3Ovwz9r2qZvV7vogwRk2/jvw5sXARRae6\nxtH3um7RRyv/H1EBXhHp/0Xj99Gwp6/QqvJt0v7z+dt/ODz1JEHzAkrWVKxE\nbxrM\r\n=PyUi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBFaIbx4cZH1lHCO5ilnUn6xpy7mzBMlvIMd4j5El/SYAiEAl+e3LFEiy7DAxOFdqYMSdhWHemO2p+mI0sGNSUAX49M="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1609385764.0_1609385812264_0.4380585772893293"},"_hasShrinkwrap":false},"0.4.2-insiders-1609436485.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1609436485.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1609436485.0","@vuedx/compiler-sfc":"0.4.2-insiders-1609436485.0","@vuedx/projectconfig":"0.4.2-insiders-1609436485.0","@vuedx/template-ast-types":"0.4.2-insiders-1609436485.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1609436485.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1609436485.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1609436485.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-RdMIHe3haaKtx/xLI3MNtDjPOEINKWufivIZke08iQ7ZXDY7kMMnSJbO1dXk76Cvp0Jmj9aSHlAulgSJC/CULA==","shasum":"88bdaaedc434581641ba358e2392b3f26a4cc087","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1609436485.0.tgz","fileCount":9,"unpackedSize":2563744,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7g1pCRA9TVsSAnZWagAALsIQAKCV3rxIMiVmLqbc3gMT\nG1o3hGxgabtegqHy250pYgJklJ/QVxnIXEL14asoKB4eJ1Qw90pfI4Pw/b4C\nX+sqgiD29CY+Nfj0yk1DIWezA2H2LlH/DShR5tT95EAElh5Pb1yXwEUosZoz\nYFq1sT/3MXLgSq8AuQEcDgZg/TvFF4WMEvvQHVGoC0Z8is9lLuWM0mx9IsqI\nJmM6CXDOwgFJX0E5WPfRmp96NsRp3wrQdz0R152dxRVqaw7lLeSb1+Er1QmM\nSKEKv0Lqy8nRXrQF1FoYvJRyu8DtPfU2ZotGM3SiuHHrG+q6mSg/1DGeuVb9\nL6A6+d9l7qs7n1ekV6MuERF8kMXcARFSMSKpESFV0T4ua08jjgHaBm8xuZy4\nZzbG/RDInEcFr1pbWwQCwn0tVfYoJZ77bPO5crhimPWrShmh8rto+Vfhh5zD\n0+VQ4O79L3uh4KewYGyRNLyHUUnJn/o3OzvZSxNTa1cckQqIipWYY2Yy6HgD\nZzR0OJKAu3dGPtVgKA+IydppCASCm5xtKqzC1Z/EkFR3H4RLHJQBXeybFCJU\nvrnVPy9ttLXo/HTxrOcIjWz0xTWTCV6H6t+AXVNxXsYJh/67VrSe+2HUKLgY\nvz9NCrEVgYkcTaKajNc7IIsAz7OLP1bcjSV8BQRKKqEZBilPXI6RjfbmyTdD\no+X/\r\n=OLwp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDn8zGU9Mj0RhzIuZY5Z94jQ+hCH8H6FemlUnQYKjj+HgIgZiaq/Fo6cpJpMMATx5onGX4riLzk+cxqkyayQC/EeMI="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1609436485.0_1609436520241_0.1674671927927729"},"_hasShrinkwrap":false},"0.4.2-insiders-1609479032.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1609479032.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1609479032.0","@vuedx/compiler-sfc":"0.4.2-insiders-1609479032.0","@vuedx/projectconfig":"0.4.2-insiders-1609479032.0","@vuedx/template-ast-types":"0.4.2-insiders-1609479032.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1609479032.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1609479032.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1609479032.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-ikbzACM/5P12vYRXbcw6ARDKmZPCRCCfwK3JuH142j39WMil+1W4gDLAoBDWzPQjDc7ybosu9UsuA+tTObHTwQ==","shasum":"77e3777139ed4638dbc1a6ef95f131a1e18ed37b","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1609479032.0.tgz","fileCount":9,"unpackedSize":2563744,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7rOZCRA9TVsSAnZWagAA4/AP/3TkH8GfgjPze8V9WMJI\nEA4QJmEOToJ3bI+XUNmgJJFQ89kGzxTI3Jip5cKfQi0VVUEWTWtw1T98wq0O\nqJdvOnHaAck9qA7qYWVPQbvIUBkKAVNij0CkL6h0ds0zqdiPxCWVM6i8o04Z\ncqJbL+mREIK98zVldryW2jYXPuQf0Xpez+Pql5RF2aDnJNtDMP4utVucsadv\nTY+YB65CVNp1ZuONhi5cqlNTbui7D2JJfY+XLxjernleq74G/Ek4+bJ8Z+xB\nyUjfTGbFjjRT8/z/emGuwFaZCCYb0mSSgnxJR5zchOyjUEvZXXzCYhZ/Iw8C\nL7bqRJiQiuBwbPoB8SbFvkVq3Cy5e1WcHln/cwvXCzxZNC6kcbEwGec1wWpy\n+ec87tYQAruWVjlNh32+03ICRyKnYTTBadd/811HgIJeodNAWU8l+WL63i+g\nq3Yg3zOFx2r2Z70mXmXB71sCrCnyZJoW+UgogQoh5AfbcX+idVsoG29mRuaG\nXugqZgtJw9fzFgnHwcEAcev3G/I0xMPCz7k0ACN2pzRdmBb2V01K0AZvVzN2\nWQ89bNI9YZKiZT4dN6ePZ9TmGEu/921FTURodJ/e9XQYHCLQtjp66oPTrOVx\n0E6xuNon0nL9PLQ/zEhbVX8aWk3A+PLl1sDOd2bJDQ1rQhwuPMLWr0/2crG6\nx+3o\r\n=7kCO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC8sAoGXntZZfKAZQvoRCkloIP0/ezEWl5KScUHeeWEzQIhAO12eqZMgWJmSjjEzTeNhe2aKPF3gX0eYEhjGrQaM3dG"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1609479032.0_1609479065111_0.5121078455153778"},"_hasShrinkwrap":false},"0.4.2-insiders-1609960000.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1609960000.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1609960000.0","@vuedx/compiler-sfc":"0.4.2-insiders-1609960000.0","@vuedx/projectconfig":"0.4.2-insiders-1609960000.0","@vuedx/template-ast-types":"0.4.2-insiders-1609960000.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1609960000.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1609960000.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1609960000.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-aWV9h34GYn3XVul3QKrxDHk2qZ7Q3t5mRdkO/uhsFdfIUIg3b2wyXK0yqF86p98FkHeLfrWIr9lbXfd0a5hY0w==","shasum":"bc6802cdc18896ded81327c34fa760e7b122a6a3","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1609960000.0.tgz","fileCount":9,"unpackedSize":2563744,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf9gpkCRA9TVsSAnZWagAAZLYP/jWDPfVLQZvXQxAlXT3L\nTXdP3rOoZHU/knoWCjOR5K9O3nVGbf8scduHwzXZRcGAKc+6lGstHUgN3iud\n9QHITM9HzRlrJIGMpcepZJ8mhiFjlU7W2QTcnhplFdj05iJPZ5qgSacePWJG\nktuoAro47Og0YLTfYuQT/H/ob10Y4W14i7UoTvUqmXarAhrZeoJatqOWNjhz\nwWeObb0lgPn4aq24Gpfz6osp7Sl8mfN5AdQ5jFI/CKBSmdxBF+iOKPA9JqzQ\nIo0U73yZz0e7HFTLyIYGdbZDu+E0X7QxoXWBJema549nfJnllgRiZ3ZFGprm\nNWWmUaOQ2giItOLFTF+WignMfSKuS0r9oSVfUKIqSl6zo5UKfSCIn4uJQsMu\nsRXgi6AYlB8NgApw+iLdcFPj6YjjbdBAUIgshDCH1MO9wsCaqcUysN3J0mrt\nJKHBYgACQn0LqRjIwhEwXhbB3GCCISWqix48S650ZRHfd8gZG7+goio/S7r2\nloUOtqJQ5GLQMEHFyK054OJLdTER3joYppe6n8Wla0AXzdEalUyOelbq9rYL\nKvTIrTFIlUOBBL38rUIIL/QULvZR8WZHrJxy9UsXi7w7Hqlizh/6UxlQMWJm\njG/jel0RmDYxneV9jdAVLnuYSFiYXxOusPnpvSjI62MUKBhDBtt4M3KyJHBM\nDkvU\r\n=R2lq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDn0PVDG6PceJH22gLs80FZd6us0qMnmfRRQnqozfO2WwIhAM3cExQczYLOoDTUG4G48AAeT3cTcXZ6bcXSQKwr5lji"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1609960000.0_1609960036215_0.18225705747082865"},"_hasShrinkwrap":false},"0.4.2-insiders-1610169628.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1610169628.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1610169628.0","@vuedx/compiler-sfc":"0.4.2-insiders-1610169628.0","@vuedx/projectconfig":"0.4.2-insiders-1610169628.0","@vuedx/template-ast-types":"0.4.2-insiders-1610169628.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1610169628.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1610169628.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1610169628.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-j6kU3gDB1vgrX/OSxxN7M0ccZ8ssW8MDTQj3kSOjbzGtd/zvuIvLq/j8u4ozhmpm/PtDRng9VNDBaZ99TVBMtQ==","shasum":"30186e86c31c1af67be9b091bede86f11c972c96","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1610169628.0.tgz","fileCount":9,"unpackedSize":2563744,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf+T1BCRA9TVsSAnZWagAAM3sQAJoUAZ/CcqT1r8Ux8FjC\nykAdZOETM5lrObHY8RWvUrvyDw1Mhv13+/5j30ttOUXI7p5Q6JTWd6JdNt7S\ntWO+hhiVAwAsli/xFx1damghOO7VbA4nxJQnrgjZWxU4Q9N3+3RWCblxPmNV\nweuNuSQj3hd3/57yYuHR0kBNDQTjk8039aEi+LmyXnF1RQs/mHIAZoazry+8\nquK3yFgbVzgu+vwk57H5bJndZghmJOZVZn9Ua7ltD5XECmJLoWofxRfpCJNf\nv2oEjVsxVe3XKRGM7v/ZNIcEr6c4REuG3B5QbQXndSM7OZ3H0Zhv4SbnTvdr\nCHvnwXKJmqtcfVSThQb9r+XFoyGbic4k2+VXX6MmTSF4miHVbfSXlciK0gJ/\no9ICm51SSXieT90nuhaaCTihohXpseJk+TxvRqSvlCrfV2CZkv1zm6Ncjl03\n4D8/22g9BtK0W7BtgNTJR0fU+QNdVXKJrBFwgOEdh8YYwtisIddsIAf4nkOE\n/ye7f2FxgX+E1WChwySld3t2xAOCXeJT4ktw/p6jurWy9oipeIGUzHLgy9Ps\n/BMC16fKPIBXF37HeQLoi3LZQI2UfZhskC6dJa6EVtqDMLMiHGrG0TYlNNTj\nnb6WsyEYn/oQUseLbhCIxnSxnceniHg53WuEZRw1D4TbcJl/iEp+u7+iTZ1z\n0opk\r\n=/Te+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICu5FGOJ6a7/gu0lK7Fw66mwir1c+54O1UkJAuXFHPFlAiEA7QShysaCke+zKIeh1BU977v/PU3/eNPS2odwQdUHYYo="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1610169628.0_1610169664974_0.5463542772154268"},"_hasShrinkwrap":false},"0.4.2-insiders-1610448877.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.4.2-insiders-1610448877.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.4.2-insiders-1610448877.0","@vuedx/compiler-sfc":"0.4.2-insiders-1610448877.0","@vuedx/projectconfig":"0.4.2-insiders-1610448877.0","@vuedx/template-ast-types":"0.4.2-insiders-1610448877.0","@vuedx/vue-virtual-textdocument":"0.4.2-insiders-1610448877.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.4.2-insiders-1610448877.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.4.2-insiders-1610448877.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-1liq2TleLtz/m+rVbuWJE09sIy6YSqHKIMrsXotGrqEjW7NNfzVBwCFR7aE05ZsXQMNA+Yy8uMrTM0Gj87PErw==","shasum":"4734e681b8e82544e273890cd313179580f83093","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.4.2-insiders-1610448877.0.tgz","fileCount":9,"unpackedSize":2571300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/YATCRA9TVsSAnZWagAAB0sQAIFYeYqFsJ61w6vQCGJC\nf+9ue8rR6jqMXw70h74QW91l/snaSdU/zQMDRQI4iVFtYlautABHQM+X4atf\nOa2jXO0/XVJ6W1peN6TTjC5bUvGT2d4rvKiDWbkWns4avI3bIAQwspk2zPoe\nSPNJFPfCtd7fqSw+8X2sRXaxf2iocn5VZLG0P64YPHGmeZrKY/g6pvmG8gfH\nWCONffuhGks6UuOC8J5iwXUqllAbC/BG3163t/V6CfYhBGtpagujinFwU0Ik\n29KHIQZo258QUaRdFj20gsaozsCAa3GsnhZCh25oi/mId/TS3COeYym9Wsqn\nH5ufNb/vKjQ+AFOB7HuZxGxsmo1BIHizkw9UbtqrmkImRMk0AELtGh4NnOeZ\nkUUfPdpIkCBsLo1mjZSXuXKh0tGquNumznK3hDHpzep8MOjUG/Wpa8UP8T4A\nFjpJU1wbw5Dh3dEJc+scdO0aG/gouQ467q4Qc1MGBL0Q5ClgpoTDmbJI2WOF\naF2fbFMkXrk82f1dILzGs7HTBBp4u1oeqCZz12+HnPjejZbak9hUYa5J1L1P\nhijXy5JjVmgJ2OuVlhg0CzxgC6vFgO8ImXbtBEZTQQzCPfzJc7/AW0ClyHpX\nrpl7L5VtK75UJKfWBWpA2/uxPFyRKoNNU/2alJ3Lh6QofPQc5xuhljtr3Jzz\n6At7\r\n=F0lE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCPNtrHGWUEp6H7o8zd7O6MJs8TC+I7PgY6lr3DqceGmwIgOLk6UkAtqxfIL5Ii6PrisVpS9G7mNgaqEEG2+Lt5VXs="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.4.2-insiders-1610448877.0_1610448914652_0.8101463690154649"},"_hasShrinkwrap":false},"0.5.1-insiders-1610450632.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.5.1-insiders-1610450632.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.5.1-insiders-1610450632.0","@vuedx/compiler-sfc":"0.5.1-insiders-1610450632.0","@vuedx/projectconfig":"0.5.1-insiders-1610450632.0","@vuedx/template-ast-types":"0.5.1-insiders-1610450632.0","@vuedx/vue-virtual-textdocument":"0.5.1-insiders-1610450632.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.5.1-insiders-1610450632.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.5.1-insiders-1610450632.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-WlCRica1Szj1mh4qMKvr/h2HK5TDmRFxCrU4SGVdTCnIHd42NolRkz3UuIAdj2gfFOiNyTQHEASuOasvt9JMkQ==","shasum":"c1941f7d50536650963335dccdcdd19c41ccb397","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.5.1-insiders-1610450632.0.tgz","fileCount":9,"unpackedSize":2571300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/YbyCRA9TVsSAnZWagAAW7UP/Al0qMuyBmttMRp8gV+A\n4Esu52cpFrXrxziXGZONJMmDiQ3k7lrmuB7JqnGAEwthk/zD5xirFiyG/Z1I\nwEksKlRWU1l+jfb86JiQOhmUMja530Yjbhde1jqCi/DIqeNU8JfbGApYeZ2d\n6ymFrzkC0f4lv7Ff1/LrUOEXa/7TbXyOKlQxK1EvfnkCMJDf9fEapW85WrdX\n9TujABWxQQeaXjvFQGwNJTI98X86Z++7uUSCtlLtnSIsjQm9Tejt/9gUJ0xS\nisHZy23TjIVEIPQTEoGHKBBPmIR65g67HHcxVoyUbKS8YRkANq5tqEz1xE6+\n73XarMdWca3FyNJLNuEfMeAYqk/a6Lr7k1SeFryniVbxzY7uzlZFmTIGKJZF\nD1/LsD1U+spTVG/1hud60Oh+MNqgn1EBbf3OtbRg5clHOhZM2+G3QHXYYHG5\nqqH1ltxrccHl45fQ+0dlyJrrxEkENw7VR1f5WGdYvEFtVRkKRr13Yja+fX35\nt/YxovIIJXcir7DuRqXsT8hAA1/whmTHrBjec0eII+ZrWWJsjXZs6bHUlM5d\nm01YZbukwfXMLk9hZsWBUleDqQWtB5vHj8c4WkOPVD55XGtpvQpdAZZ0Qmho\nWnXGhOYQGd9u+YneVOBzlUTAI3WOOyI3sAVyEDmoqLrEpPwo2b7PevXbvaix\nmuhx\r\n=7EkH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGnllYAhAzNwDBLQTyPJilnF/Kq0g4SI17eYWdSDwqlPAiEArv0wLl+y8A0/BH14exl6Xw/b9qCD806cTgbN3xFBv9Q="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.5.1-insiders-1610450632.0_1610450674251_0.20458622596508902"},"_hasShrinkwrap":false},"0.5.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.5.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.5.0","@vuedx/compiler-sfc":"0.5.0","@vuedx/projectconfig":"0.5.0","@vuedx/template-ast-types":"0.5.0","@vuedx/vue-virtual-textdocument":"0.5.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.5.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.5.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-D8E+I4blOFB+rjLSmiiqMB2sLgpzUQROqJEuz7CZhnphp3k5FcLfPY1aFUsdLg6pQQ85JyujGfTFdfytLL80Yw==","shasum":"9ee65cf4f9f9d4cb2afe78cbfb96ff7b5bb34f93","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.5.0.tgz","fileCount":9,"unpackedSize":2571146,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/YfiCRA9TVsSAnZWagAANusP+gPWziaI8B9fIONIAFZ2\naWvdvAydGOwUcJhZKXkVtCCDqqC/IwHPC5yjyNNUrUpTJ8iBWkGb/UDiSGQI\njZpMhvT8PEJKzI0u4TmE8M/XoRk+7Z25zw9Utp1mDKaBy9vQgdfPaBBDXgzl\nHjIagDGm5qMi0vLk69zlkri/T6YXm85TKQ0zu6aFKVGTZ+oFgRKb9350wYKV\nzvOzorUet81PzfU2gmh4KSAsj8v7Bwea7iOZuGgY5yvQQ6cn4c6AQXJROXVx\nbpyFkab9nYTxLWOKWMY+hNN1Wo7k3QPhRhhmajucgjpGaFOjokoVDminoPdk\nAa/IYfXQgWBNcLqp6VXPXCCnsseNLI1q/C5JQXUZmpr+0M0KRQV58PinAdwL\n31bc587GjuaHkVUgEhKPc4pqPreLhh8j8R9A8maJl1X0qmNLKC0nHelBAZkd\neopxKrKnRRti60vK51w6DXnhDgD53YoKF2WJSohh9zxTnmGM0/+ANSlkiWmN\n0ix+BCu3bCYvFwmBQygxARC0O1nlDq3f/4633me+u2pCn3SVNMCrL7ZTsy7J\nOhAfZoP0zOXsnOFNHZgOMXf2WTZIyR/64ciEDpwBOheval5bv8lCxvPoVyTG\nS+O+5rYl4EXXqacXr5upJRYrIlfHlO100+GRhnWbBJuSiSdCE6TWVfSjkQJ9\nyObP\r\n=7NFj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID4oHcqU3Nr+Sh6FSVeov38dqHx1kiD1g8rnlqinRyE2AiEA1amqwEmUg+iPPEX1FJrdyIJQct2YoqpApATT8gXF7DY="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.5.0_1610450913530_0.42999277319762874"},"_hasShrinkwrap":false},"0.5.1-insiders-1610688008.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.5.1-insiders-1610688008.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.5.1-insiders-1610688008.0","@vuedx/compiler-sfc":"0.5.1-insiders-1610688008.0","@vuedx/projectconfig":"0.5.1-insiders-1610688008.0","@vuedx/template-ast-types":"0.5.1-insiders-1610688008.0","@vuedx/vue-virtual-textdocument":"0.5.1-insiders-1610688008.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.5.1-insiders-1610688008.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.5.1-insiders-1610688008.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-ZSb5EGhvSX6zedaydAm/xIy3/7Or+84bKXla0Y/bRg5C4rmvjPLrjs06KB1ZG3kpcjUGkpPNcXKdkGUCy6J1Og==","shasum":"daae9b1875809185b37cfa9e3dc5d6cec6a8d857","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.5.1-insiders-1610688008.0.tgz","fileCount":9,"unpackedSize":2571300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgASYvCRA9TVsSAnZWagAAG1IP/2qVaBTjGuzaXG4k4H9J\nTlvdyCDTKdPTBzoYXCCOvA1UvB0yV/Ij5p0J0ecat0jfEk8a6t+d3xF7CJO3\n3GZNshTmE+8nAeVQzISGSqCSfsllBJ/MvkXsvaM8LGCaEZb1VbrjUycskK89\nwHF6oqFU7172HX9ly1TF6yokyBGaaT5S2H/yIZqIU6eUf/g3mlPeZMNkI5o0\nogdDjzPLfW/Izwv5hvOrdX8Q9vEK0t6kBqTLGS91bgTYnCxJwPIgcQgjeASt\numxsXQHl0IWiMGjAzLzkvD8FFmrDSlN7EiUDGWGycSdTMw0LyRU8xVRK7jAU\nAjarqnEQFENQnwsW8RrOhP4o9uthjKVZGqyhbDVTjyNO70K+7W3grcEgv2YH\nKjYFiFBwa2cvcsoExfalNTeJDAFfGTqXWXK4oIv4bjHDJA06VbC2UhL2+xni\nGrT4RMCT4fyCR4cT9xgX3PtHbYqeQ4nYP6jBv8hliXDbjeXD2vuLnzagAMWN\n2YpicLPLHtWqEeYJ/2FWaCYoFLBdKckqsVK3X8dtaAR7wt/EDhJri0+8E7fV\nr3nqzjr355HhirmGuni518CMNnQxrr4TVAAYZNjRjW+TrVIXW984WXrNGVls\ndA4DvSUgSQib9HC+DllZHLzjirbN8l/ya98Xkvk4JWDLMklaNfBXBDC0MIBg\nlIlD\r\n=XYc3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICnwYNpZUSVeS7CEvXENVKxk96a4yXEuy4KJ0w4hlCsgAiEA0wNQ/VzFhSxqXnbgqqi1nlfog9TFDENOD5aDMwMkmGg="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.5.1-insiders-1610688008.0_1610688047258_0.640875610943588"},"_hasShrinkwrap":false},"0.5.1-insiders-1610735282.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.5.1-insiders-1610735282.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.5.1-insiders-1610735282.0","@vuedx/compiler-sfc":"0.5.1-insiders-1610735282.0","@vuedx/projectconfig":"0.5.1-insiders-1610735282.0","@vuedx/template-ast-types":"0.5.1-insiders-1610735282.0","@vuedx/vue-virtual-textdocument":"0.5.1-insiders-1610735282.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","@vuedx/shared":"0.5.1-insiders-1610735282.0","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.5.1-insiders-1610735282.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-B8VjrX81gIKOPryfG7fFdpdw0IjWcyjfHdfbofmG3kfM4ti6ul9eWkS1HNLiRthh0RrBC8awPfOqo08lHa/OJA==","shasum":"f68da0d6fda871a91120c0325171229e1cf0d40a","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.5.1-insiders-1610735282.0.tgz","fileCount":9,"unpackedSize":2571300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgAd7WCRA9TVsSAnZWagAAkfkP/ie3Qeytecic7tcWHyNN\n76MC7w32Z6v2uEeVZwNV5vTctn+psdPJjRd9lgp0jEZG998vG3L5ixeSdHR0\nJuhn1SHb0j8K3lI6EPtqGD4nCHyCztDAmtyXmbF/UDn3zVdRqoHyzFYHUIlB\nV68dKz3xNzWdvS5iqqArCmn0Sh7Rz053Cjkm66XoyToVFLWV3bTQ9lKPqEw6\ncFTwvUW6kCq9nLtkje6nPwJ7hd5TVHuM/MdLhbLxObNRO8SgvtEfxe+ekGuC\nWRkUlc1pU79fYiSElhZs9fTCTKFYUeDmw3ZYOmGITx9hhbwtZoTr4H9XS9Yu\njYtxPHkI7OkwwSf1//3CURhZDTIsOynT9mQ01bopW+WxwbjGJJiYAzurQWOb\nh/WtnTFhq9N7+4JmjHkujUFQl3Qlmkbv4/VIzf7KlVBUa47vzamaQayQaATG\ntbMTgpLE6MbzN6qPxc8ZbooLj8aLOXAYZQmDL0EbNpVQzth5D+1ftVxLPo+h\nLsHGsbTnuOjntw64oNxVZjHkpbrqhBTePhqxCM13JXXvKb5WJHOIuya5ctTl\nhLJYNw4kCUyB7ZEzQs37CTca3HXJcG1lF3hahvjt4KpXvdcmW+BqAVIcOdRN\naJYMpNlTwoHf6t6mSQt2/4GUnC/fknZX81DDljn3rnqeQ/ync+83Rk4c+3Oj\nVtpG\r\n=dVQj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEsU8hMyIfdeqG7Ziyuw6XgYqZCNrDW26YHtbRo0+SJUAiEAl6DRa2WueZggmi7m09ceiMytMQlzChlBAYWnSQiwjxM="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.5.1-insiders-1610735282.0_1610735317630_0.1442044205229489"},"_hasShrinkwrap":false},"0.5.1-insiders-1610828338.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.5.1-insiders-1610828338.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.5.1-insiders-1610828338.0","@vuedx/compiler-sfc":"0.5.1-insiders-1610828338.0","@vuedx/projectconfig":"0.5.1-insiders-1610828338.0","@vuedx/shared":"0.5.1-insiders-1610828338.0","@vuedx/template-ast-types":"0.5.1-insiders-1610828338.0","@vuedx/vue-virtual-textdocument":"0.5.1-insiders-1610828338.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.5.1-insiders-1610828338.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-8rcXvcJaDfUEfLEo6kCJWfwUZBrCVLI5vQngo2bUdOYEQRSalsFK6QzCpuZqUQOqmlbk/1I/dWe4hmDBzpgm7w==","shasum":"1346e336c1a5019ea4ef5b963b67ca618592ddcc","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.5.1-insiders-1610828338.0.tgz","fileCount":9,"unpackedSize":2571770,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgA0paCRA9TVsSAnZWagAASckP/j4K6eF/+b7ZeXNpOTkd\nVIGs2NPnpaLI9OY+S3fng13zm1fO21MQ+yFP7MotmBPl03sNC5svpR9qVyxx\nsqlbGOKFeHknTWBKuJ5vfb1lMK64Jvla7lveQB35qdZMJliomSoSJ1+r+u3c\npQOLnkDiWRvWFvHDhYFPQXyU5UBWNT6hP6Kav+X1ycS3DFWJY4ldxvYXLxqo\n+11XY+Nml58VQYKqHsPgLKjEo/+m1Uvo/p/doh0LuxCUztylgV6W0OWz04Dv\nnIF2zSuRSF0KIOW6lh/CXSKAdWofpf94hS73eak2013/6Y7gCKG4VnGjKnXJ\nU/zRD1jomxf9DeX+IjjIn0FT4cFOVwPUaqBN4nyv8g2Y1x4tx5VdOqamw5W4\n8TGYoXFBCkmp/NRofGm4mmCD+PJTaFQjO2S9xvVseux3qBKT76bY+4W9dNjz\nBBryovV6dqZm/GyuSAPuIiVGjCOsMcYfoBCvxpmr92Rbo/pavtFU0wMu3j0j\n4B5Pqibs8W5Gj5tmUhdh5NY07SJ5QZbpY5SIm+0gxgELc/LYE1PT0hL5VE6l\nvr1Pija1uMNqKGr0BYB9807CZkYTd8R8+MvbC/x1d5RZiabe5fAjHN17MSSX\nzKkJZ67MzaDLU1BCNtPzpG+417NWM+LbBthqnM4fKmsGWTOyI6EPFk7fDbBt\nQ5O2\r\n=eNub\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD4QQygO69jvEUSpu7y3aM/NRF4Is0K64L6yLvm90Qz2gIhAN6gTx5df6RlGK2OOUG1N1y8jgmaXkw1Eg/c0N+lQscC"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.5.1-insiders-1610828338.0_1610828377782_0.33801016068239553"},"_hasShrinkwrap":false},"0.6.1-insiders-1610883378.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.1-insiders-1610883378.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.1-insiders-1610883378.0","@vuedx/compiler-sfc":"0.6.1-insiders-1610883378.0","@vuedx/projectconfig":"0.6.1-insiders-1610883378.0","@vuedx/shared":"0.6.1-insiders-1610883378.0","@vuedx/template-ast-types":"0.6.1-insiders-1610883378.0","@vuedx/vue-virtual-textdocument":"0.6.1-insiders-1610883378.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.6.1-insiders-1610883378.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-Co3rRlsU558vD+kgNk/yflNFhCaNaomu3SghG/kWD4gfxr6/MSWI2tUA5qKj8TCBSFFL+e9tyRFSrmkXTaPcKw==","shasum":"58cf26b1137e730236f95932beb502e480de0a17","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.1-insiders-1610883378.0.tgz","fileCount":9,"unpackedSize":2572787,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBCFYCRA9TVsSAnZWagAAqQ0P/2UD4F+hl5KH26I/NW8V\nWUIiI219AC2UlAL4n25jcsuNoTOG2tjJPh9AO6qx0jEkEjPHRoTPbVJ322XK\nFlKurhHgwapOr16H582AlJ4T5OadDGmexdBTm8zIKPEn5Rk6Mz+YOZTxKhDP\n1PJnFlGzDwxkd8SYxzddcXyAy5XwJVRwMUzrQIv5rzyTtPQLp2tmmxHDjCin\nPVKnghAfJQKzmJdxpYvzif6Lh7lz7A5qjhRUQKy7Hr4f0Kocqxd37XBHG5vY\n0GXmQgQP5/oOz1iPQR/H1Turx5DY/g52PzpK2E4Ua2fROZWe1m9SJxwd9uXf\nycavxtzgsYidQOLRSwXechAA7flVZLT60LTGQYTfQ0ge4SIbLRXrEcZSnDk/\naM30QIn+Lt4bB4Vp0z4piZM65wIQjtv6/46srzOCbx0/36Z2t8+UQ9y5ImpP\nG7fIezDzhEaR/uyj1p17k7atzOwaS4+mYadJi/sliIq1JcWWxuCmR2bCLGdK\n3PELx7FgzcohYXqfA3dyJR1a7gqaQ1C6xkR3FeQq+HF/39VRtTUa5ruR/NFo\nQjM7Zl7fDONY/HCe+abj57dHT0qamjAUYDQ0SM3OfBOfDDhaItHeYNHlLhvt\ns5EPVX1ZRLrprZyQMysCNLLaIAqW2t6No66Ta0y6YLpOJ7VpxT5jY05sNWu5\nCthZ\r\n=brhm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHGLobi+SfMNZ0W33SGHeiVz1HgDW2ePkyqCADBcwov6AiAfAmveGqqbU/NjcJVCL9QDN1gHxOiKn0EXQGLPeEIQ+A=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.1-insiders-1610883378.0_1610883415879_0.8309086546160815"},"_hasShrinkwrap":false},"0.6.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.0","@vuedx/compiler-sfc":"0.6.0","@vuedx/projectconfig":"0.6.0","@vuedx/shared":"0.6.0","@vuedx/template-ast-types":"0.6.0","@vuedx/vue-virtual-textdocument":"0.6.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.6.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-hTtqSPrU6hpZGQ1LH/mmK5G1gluXCWmD/Q46IzviMIzdJVC14W6BkxwoOMyg9+fIKtkMplqzBTPsK65FhDlOjA==","shasum":"69db85c01f7f9256a51b80363e127d78c15efc78","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.0.tgz","fileCount":9,"unpackedSize":2572633,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBCHuCRA9TVsSAnZWagAAbLYP/2FDDqeHUITRH16h79xX\n0rdShX+bCJ8ZGn+Hs2nvNoLk3/6+P/Y4zxnb7LGihCZgcNf+ErJ749uouR3S\n3psPIp01hzJhy4ZM8rw8/zBlUrWddcKiv+fX/NWz+jlFMyWzLzLVQ/JOGJTt\nU/1l/NSJvj28ul0fX1tEZE65+p7vTmJHe5RQ+E771gFMDnyMhKiHA7W+QNTj\n8S9uORcIlyI0NMT3VPkzBJhc5YznFqzzLMQv8bghcKEvwdz2R9uppAX48Pol\nJcDL6AUtFGFFUpUxgbJUpvGe216T/lDqyBeO6Y7IzNsxqRILshzsxhN2tBkj\nrjvtLaprcUAQQjucvndoOPeVDjtXwxrMFxOw1APPINLZc5betoJYzvtTvMiK\npNcPU3yFmdh0b62d8goojldh2d0j+qro4VrJZhEXVfWOHq55HKXpwDTQ0rLN\nH8+rIOVcp4/WX6jg6Hgy8PTph5zGS4tz6IhZxAXMlILbch6fuOTySSyxj/6S\nv0gaqGQk6bYcuPcfsxjdcu5tMpIA6NuSxQFQn8kLxVmre88QkrvypMF31JGZ\nUUVgvgu5bPlS16g8/tCvxMCJD9XRl2/N50eykyt7CypDL4iUvQIDDkTPKKew\n1bD/KHdyUZ5UVftBAWEnIfIKa00snvcY8ozonvG0rLVRPERQPQYjwevYITl9\nhVB/\r\n=SNrO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC56QZkjJGDTDQLtX6voeilmByM62jw76fSsBetlomyOAIgGqjMdXATiR+SvjcArd9yLvNzBhfwvkRVDg+fUh7IWnI="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.0_1610883566061_0.10460193261555273"},"_hasShrinkwrap":false},"0.6.1-insiders-1610891537.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.1-insiders-1610891537.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.1-insiders-1610891537.0","@vuedx/compiler-sfc":"0.6.1-insiders-1610891537.0","@vuedx/projectconfig":"0.6.1-insiders-1610891537.0","@vuedx/shared":"0.6.1-insiders-1610891537.0","@vuedx/template-ast-types":"0.6.1-insiders-1610891537.0","@vuedx/vue-virtual-textdocument":"0.6.1-insiders-1610891537.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.6.1-insiders-1610891537.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-REkxvZ2E2ed6WVQ0gZC1XREF0V5FJck9b0FMub4jPDniOah7nmN9yqLrXt3tekgspS4LeiZKLgr65y+COcGgaA==","shasum":"eef015ebd51a1fb6f17aa45d0b1e2abd7e00a4ee","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.1-insiders-1610891537.0.tgz","fileCount":9,"unpackedSize":2572787,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBEE2CRA9TVsSAnZWagAAaXIQAJ+l3apFqfLAO4jwRro+\ndm9EGARwb9l5ul5VcPtGodzEEvbFan2fr8WLRDn1sCatAXUiJ7Anr65b4r/S\n3my5URpSdHaU/ugUpJLolugXcSUBxuCYbe6EHxpoRWt4Du1B6O3D96iwIn+3\nhBvdZYGge8Kz7VHJ6iewkpBkosp01BspXHfVqx54JBUVoeCOxFQq43KXJ+VT\n8QcR0GBD/Fu4/C3s2/dqzVJ/GppwDTpX5zAuSzIjbsS093+fE69oWtitJCIZ\n28mdq825+9mnqFY8VDPu2sAETyBwtdn+Cqtgc89ab/hXXHMJ2yvZycdcg0At\n4qOaYTG3WrGSdxYhSbEUMB9++ZE+5PbV4C6Yxs+5L79Z6GYHZ6/e2eixL2pS\nWUuCEtsElruew+qVvz809d4/UITBS9CZ0342++iAX/3vhvOZ2kxuVPnQi1rp\nXrMDMZ5AjoEId6w/qUNm/BNwAr9oErGfRsW5o0UlfAiJ1aRM+AWQ7arEd/Va\noQ8scCFWxczx27EQmSeIvTDe55HdQCEkApLZZXRrotRybWUt0g4mfhowgvLB\n+8Zv46onmSYRCq4bUvjyAEd7Xmrx+fgCPaN2+wj/bcJhk3ohDiP6HSHz+E/G\nmi/IBRigIPJj/AN8xCrasA47Gd5LNXL4qlRxSjI0wXMRVbQtPuzt6gBz/iP0\noFcS\r\n=H+QO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC5J6sF3ggqCinwyVr79kiMrnE1IvL71P+wq1yDEnF8VwIgRw7eABqUaNTKVZo4m9wDzDUrG6sBVFF2bRCvUEurQ20="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.1-insiders-1610891537.0_1610891574166_0.7993720100823947"},"_hasShrinkwrap":false},"0.6.1-insiders-1610911987.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.1-insiders-1610911987.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.1-insiders-1610911987.0","@vuedx/compiler-sfc":"0.6.1-insiders-1610911987.0","@vuedx/projectconfig":"0.6.1-insiders-1610911987.0","@vuedx/shared":"0.6.1-insiders-1610911987.0","@vuedx/template-ast-types":"0.6.1-insiders-1610911987.0","@vuedx/vue-virtual-textdocument":"0.6.1-insiders-1610911987.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.6.1-insiders-1610911987.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-wpveaDCY6zPRSt3jR7q0z7ndqnYsi+ReuBQSRMJDbxUb1ogQbLRhwueo1eqgoAp1YCcPku6A6N6Zzfxsq7ldjA==","shasum":"7e94e20f71d3339d3bdef578b7214b9751cab510","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.1-insiders-1610911987.0.tgz","fileCount":9,"unpackedSize":2572867,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBJEYCRA9TVsSAnZWagAAZUwP/1JzmifwGo1Ya/8vP4Z5\nPZ2q07QCzwFQ2A+AuWEDdri9EesATS4E7KHmGEI+ecpmoPBXMLlZF7elLF1v\nWVhEWGSMBpigJG0s+SompVtFXu/lVLDbs6fhtBJTsg63+WBFERH+PdgxGYzb\n5vgshjGI2rJdejGsKbsgbYPa/CcvtAXVXMny7y+7b2hG6oJ/2TctLA82k6oh\nHrLcCAcRVNj3v/hG3pDr8KSBTC4/2OH7AEB8JQg0GX8Vqg3iq7M90TNIYllt\nspsAZgu5IeYxVm2XfbT1kXfJNRb5Y9sfhkIg0v1lpsDmRZagV0ckoytWGdxF\n4upURuHkLbayqS4wCnzeQrI1zDD1z8YcysCEM6IHpk0Op2MOo2zdUqV2dIxC\nuQ0Abek3Scdv+sTARiPjCD4ZsvYyRh8qW+RrVGMcKZvIvgN6IYCyt85qRh8C\nBnhkffMhIDEnF+cJd93vIK0M6TLEcRKFeAv0BS4KuIr1BgOqh7s8sj4mb5uU\nsEBFzBJdvctDXM2SjpmELrX7e1bCNLgPrMkyeHb6W3aqHEe29kd5yKv9gWUi\nEfQSw0v9kmG2wLt+UyS7R3whk59D4i+A6G31qguIWWajB4v7URB5J3b/oV6B\nseGmJNNS8NwaKv6oixSs3Xdo4aAwnF/XBzJpsLQyy6j28Lf04X1XfWuQqC7o\n39vG\r\n=RZPl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAqackmHUT1VyqMVJwOb7Q9DVVKwxwnTCn6QKllZ8m4jAiAA4Q2P7NxlDlV/zQTeJo/mZt59zYk17LTvKPl+CottLw=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.1-insiders-1610911987.0_1610912023703_0.02452642583551956"},"_hasShrinkwrap":false},"0.6.1-insiders-1611324083.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.1-insiders-1611324083.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.1-insiders-1611324083.0","@vuedx/compiler-sfc":"0.6.1-insiders-1611324083.0","@vuedx/projectconfig":"0.6.1-insiders-1611324083.0","@vuedx/shared":"0.6.1-insiders-1611324083.0","@vuedx/template-ast-types":"0.6.1-insiders-1611324083.0","@vuedx/vue-virtual-textdocument":"0.6.1-insiders-1611324083.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.6.1-insiders-1611324083.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-/MVJxw2gFZjvH3VXc5FvuiabFeNIIVdfmLXy+/NWj6NuDePf+gNy0shGdWSwjkZz+nfn1yLvyzHEb8XjWLJH7Q==","shasum":"2f53d887a8a788709616a533f2843df21754515a","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.1-insiders-1611324083.0.tgz","fileCount":9,"unpackedSize":2572867,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgCtrcCRA9TVsSAnZWagAA6wcP/AuDBx3BQVjAH7tDpxtT\niAZ56vkdHEJhD+Obu6qO8X9MG3DBqLfiM9y0gI1ePH78p/NQAyeA4jngCWBM\njS0CUVJxAzCE4w2DhKJdCVkdCpyAfLieHExQwVJVYZ+XElB3Kj8iNpFW1lVs\nRZ8FEaLS2bBPn7bM3M8XGcGPThU5GB1dF1mc9pEfQ16YtdCeZsMjy02NAzAV\nN+Ilf5lXqa205hWRE2/Jm8i1BVTDUQjDEgUVQP4XVDyoLLcRkxAIoqB4/LQe\nedUbBbrKsoxmbvJ10LieyYLN1KxCgo8YmB4QRgXDIbllQEwk/soCxE6Jbcof\njdE7NdPPXKkWGQ+jTadJdNQZEtD8ZdmdxtLIzModHFrJq6YjRxQLUFpEkCx0\neA603sM7LrfoHy0jWFybXT6VYzw75ytg/WufRa9LurBo0Ula3iCTTapHcn2t\nO5Ul2u3O2mfZHy15mqon/DPM3gcKm20LD/g45ZdXxMDTKmEz5j0gM/9qmVzA\nfQtN9hdcg6eTaE5CkXU2nwPmM3hMAuG2opCaidqMC81tq2eDgveXsRwodvx1\nTlWcsWMOYuShwI5MiLOU9FIvsmL9kQisPzz/hJ4HQIvx5tgeZKizbeQtz9Zv\ni947VeaLUZozcYHZE2guMK/NNn6Wq/xIbyTX4lfgRCP9GvgHoxa0RkmyIFha\n+M1x\r\n=0Lu/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEyvResDgNjbAlEn0yhv0VAqbDCsWHc4poxb1wlH4KekAiAjRL95wX5IFQ+hfNW2on3zy7i3OHG136inp3mQFAHVng=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.1-insiders-1611324083.0_1611324123728_0.5249047907696283"},"_hasShrinkwrap":false},"0.6.1-insiders-1611498830.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.1-insiders-1611498830.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.1-insiders-1611498830.0","@vuedx/compiler-sfc":"0.6.1-insiders-1611498830.0","@vuedx/projectconfig":"0.6.1-insiders-1611498830.0","@vuedx/shared":"0.6.1-insiders-1611498830.0","@vuedx/template-ast-types":"0.6.1-insiders-1611498830.0","@vuedx/vue-virtual-textdocument":"0.6.1-insiders-1611498830.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.6.1-insiders-1611498830.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-5ZsNOBHaN6tAQM2zJanX2KgATPGhk4qN6k38KY+D1d0pl1OCt/5u2GS7l5LomtenIGQWiSe1OPAZ87px2mrUpw==","shasum":"9b402aa2e817b80466fa04d8ca7deb6146777cb3","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.1-insiders-1611498830.0.tgz","fileCount":9,"unpackedSize":2572867,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgDYVxCRA9TVsSAnZWagAACiAP/1jvQEglONjkpZ6XZXUA\n85RiNAZRoPeXlwRfW8I8S5tNg+Rv9pIiwV1Bd+behvWqBHKRJD9tSMrAVheq\nj6OVRSb6Fhhldts+/cVi77CFXxOGVWS25BeMBfYx8RyMsEcObS4XDehh6wEC\nQ8cy+35Kn7xcIwDuEbpL1LuVrVnHMwxU1zuRD+mlSlE7rgpxaygrEW09FYZS\nEi3SSH47IJgLH3nWmZvdJa2ex1vPWc5X3Omdk+bzalS7MLu4lJLM6XsTBA7m\n4UcPds0amNDRnRZgVOQlfhv2j0LZEAFzjvwA7R6C7kfSBjvNe7MIfrO1QSsX\nH2KJdMwZcby0TUr+JWgLbbYIa5Zl/ybfZ2cSDQyVvcRHZXTKF9bK+/eK+/FW\n9qiHyxSt+G/R46dKJFAdAu7ZgQ67N6aAIph5BtqAESJgNO+jHoUdrzJ+oD9R\nQVL5WZq7TX6fFCkPaGfbI9A48eKFlIbLM1Afjm7wJjhnIXQ8fYisEwGPBS3L\nyBt1vLk4D8d8iXb3Zsv6Pl6VhAvpBTPUhPmqw/KiZIMzWVTFbdZMN2rpxg/j\ngpidmsbKjos97tCfv8tDuE8KYAop+djAM1nVCc9ZsjBG4jkezdy7jXhoxVqJ\ngyLoDW057o3mXs2RuTahkY7EzReccOdJYbUz+P7Gn3k2GMKIzwlT+piFxvG/\nYUk9\r\n=ngrm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC9rBDEvw+7m/yvgCuAmfX0pWxrY/VHzUSLkebGyUTnkgIhANNokHHBmvSn/ZrG3dEW17BdfTusqWB/DMwliCDpIjQc"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.1-insiders-1611498830.0_1611498865213_0.5822601037806161"},"_hasShrinkwrap":false},"0.6.2-insiders-1611564162.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.2-insiders-1611564162.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.2-insiders-1611564162.0","@vuedx/compiler-sfc":"0.6.1-insiders-1611564162.0","@vuedx/projectconfig":"0.6.1-insiders-1611564162.0","@vuedx/shared":"0.6.1-insiders-1611564162.0","@vuedx/template-ast-types":"0.6.1-insiders-1611564162.0","@vuedx/vue-virtual-textdocument":"0.6.2-insiders-1611564162.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.6.2-insiders-1611564162.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-y4zvS45PS37RbDs7KVSVKEy4/BDg4LJcPngu+EQz0oXsT6WzITKWKTHnjhtA5liJOxLEVEl51OcZM5R5NniIAA==","shasum":"b3111fcb066b5434baa1c41c8bcd42992c49460c","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.2-insiders-1611564162.0.tgz","fileCount":10,"unpackedSize":2572994,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgDoSoCRA9TVsSAnZWagAA1YcP/0e6cZdQt2qDXif4Q7Eb\nk7R2rtG1OyR5EYE3qN6+qyw4e2Khb7nyWTKA4xcXgDHJQbmys8wxXIAu5N9j\n/jBd80wq8OZxFiB4uEL7/iVRtPSaAn/x7Ly6koQLuYgxEnsphwQ+kkOX4bB8\nKQGzFMcN6OS5lwH4n58DS3Nb7+CM/eBrcRK96new/0X8RdXL4+59SniND8BU\nXAoe0A1N1gJ9vnno0RdbqdKNg/IVNsTHhnw5HptYJsudEY1SXObqov3DLfzD\nhGVpBwsYJi9BqijGR8o1bC6hLIo+4PpymGKhnmOB0K/T9WrFBkU+M127GVjT\nJ1z5ITskWkUxA6mxYZQJkTwUE1pQBO75+ZOT2xf9OZHvlW347QdJ0Mu8qKbP\necZOnMUTgaA1hiOSFEIqEeGdNkr0uRN46OjBvkUK9QT6C3hVz0Pvic2YoUjQ\nIf7OZFaB798toRIZ/7CgwwaGF94UxS8X36y5Kiw7mtD5WGELy1uB02VlGud4\ny4d0Ja1hN5qEJO4qtGv5zuz4KL9knyLS3eH1bcTajLPkw3T4WZVFDAYSLvMQ\nfg/2G9Lc+xuO/wmmejeJdHnRsZwEzmIO1N3mHGZazEBPOm/QP6xB6fV9NiO9\nwVB7+36lwY0YTeU3a1x75KCUnd2E1mSpAcFQf0/M7YEIskv9x6C4qbOuDeoV\nxkfm\r\n=IxRw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA31VsPl3Jo5b7IG8bi6vhc3PJ43mk3bRiC2fZMDXKd6AiEAwVKfL6DtmKq4z1xPnKDxkpTO4Gh6HBb/zAKENLsHXAY="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.2-insiders-1611564162.0_1611564200471_0.8944240224195652"},"_hasShrinkwrap":false},"0.6.3":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.3","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.3","@vuedx/compiler-sfc":"0.6.2","@vuedx/projectconfig":"0.6.2","@vuedx/shared":"0.6.2","@vuedx/template-ast-types":"0.6.2","@vuedx/vue-virtual-textdocument":"0.6.3","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.6.3","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-zAhXM9LDVYvjAMnTiqf6yZcJXXh1rQrH3JhcmQNmlxk26sRysfa/VWNC8qkfq9vcOKRf1eQusH4g+Vov6qPGig==","shasum":"cc2d99bdc0abbde9bb5909341c47715af00539a3","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.3.tgz","fileCount":10,"unpackedSize":2573401,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgDoz8CRA9TVsSAnZWagAANVkP/00cAh2LTWXIkAkgS5La\nCGqoM9T02G3rmpGwUGfJtX5BdT9AylSaBkpa7Q0VGM+oWGUBX1KurlULdLmY\nrci91DFqlv6nx/WyHmkA6+tbxH8Y5PZBRRc8XAubFUW3S4qpMyBDbvGHdGoB\n6MR0gCELwPUXFdhzND1F/zYIk8gJL0FK+7I35QRZ0Q+yA4Exn9eH5CW7Dfi8\nfKdS7Jgz/DmlJjgDN7KnIu2DtmqZJenK5uHXzR0fiN0JTRU+Oz/ILCuGVXTa\nXkJky9xOtjElHy5FGiFuVDEkt1ewJr/6ZeOAbt1zblc4gYvJ0QdcQE5zD4bE\n0ndlFDCSQGtJapKzBjn0lCZAznD4kbpivRgPo7b9Hfv9FoVpKWUxjdxRHEd2\nN7o0aiyMhWEkpY9mKxbeT77+sMQ8GUptV4jteyI3kUS0PonXRGecgH7qbh+E\nWd/fL6rMtR5mChdUtMg/TG8SRvrD0MfzTpYDlnSsdX0wF0UrtiebjC7s+MyI\n4hLbAPoicJKHuyVKUbIUAr9gNMcrgaiOfQz8E86JpCRYf1TkejGYEUYEak9H\n8pWcvSoOiOX2nTtArrWnR7DyBqHIGgEWq7lJ23Z93Xw6hy1A+6QN79EXFzGZ\nePTv5N06Bxx9rtnLvpejr9ljkkVeZwwuhcBE3T7I4A+jqyXyG+IjWQR6xxFA\nSili\r\n=tvaq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF7Pn6eTk5j6sOmivfmUgixAJBIiCKMUfAdYGismgd1FAiEA7S38sNODr81kwEKbVG+TY6pCqV9VlI0MMaVMTLoczHM="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.3_1611566331889_0.689204257632769"},"_hasShrinkwrap":false},"0.6.4-insiders-1611829384.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.6.4-insiders-1611829384.0","description":"TypeScript plugin for Vue","main":"dist/index.cjs.js","module":"dist/index.esm.js","types":"dist/index.d.ts","private":false,"keywords":[],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.6.4-insiders-1611829384.0","@vuedx/compiler-sfc":"0.6.3-insiders-1611829384.0","@vuedx/projectconfig":"0.6.3-insiders-1611829384.0","@vuedx/shared":"0.6.3-insiders-1611829384.0","@vuedx/template-ast-types":"0.6.3-insiders-1611829384.0","@vuedx/vue-virtual-textdocument":"0.6.4-insiders-1611829384.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.6.4-insiders-1611829384.0","_nodeVersion":"14.14.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-NOsnW/mNjoCOid9UucLvxks8Qcn5pdb+ngApGOo09JLg+dxaaBH4jhjLI4eD2Zvxl/Hs8zOr4QaraeTaWtZlQA==","shasum":"579ab1f5dc05257ae27465184abf44d284d409be","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.6.4-insiders-1611829384.0.tgz","fileCount":10,"unpackedSize":2573555,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgEpCuCRA9TVsSAnZWagAAB+0QAJWeogerCsurd8Ro+cXg\nSsPUHBV3BeVXuL+vj8riy6D/MYmjIF8F2JAGNqaDTF1iiKH4y7Ek2oT/T2Ta\nxm/3OxcI3cVJrsL5Fojzm7n/woKp9Uy+BI4YAOzzNqqirqj+qJt2CIpnBNkD\nm45Qnz/99J4M4dyu1NOEYGY6gXq1ClI17aYGmo9uNkSCyhzPgPVn9+JsdKYW\nbFBSiMu/8fOwLm1Z43iA9/MTS44jnec/Blzo6/oD8rdea807xTqadNbjYdWx\nJ2KdPxwkl2pFlPr8kmz/N1h9+G3PWOmhpV3OjvSdZWu9z1uL0AdzzX1a1H+A\n9jrRIL/+CWA4Fk903ilO4dqG4XbG88OgVwzUGYZh4H5k4ttzeULhvDtfbaJ8\n6dkguu30Xm306/XcacEoAXu2sFk7oFD0hiOW/A7S4als6Oo+JhSJvxDnvC8b\nJWkVaj4n55pZsf9rRLAkd+POlBgUe82pv6ERMoGgu5CdlFoJqc6jks3Z6YUR\nKybH4dJlL8MDl2DsnhVS31cLMVofUCIw1F62gSJxkfEt7OYhD7Wz3seFEdS3\nTJ7eiPAgktKsslrze/NJT827cjtjh+0G2QX84HUbpIeziLyoxhKoII5DRFoI\nC9cN/NUOu0WxCIc+Ecj+7PL6phkbk2aLRWnU0nVcJOvewtAb0+le1uxqEOhB\nQmMB\r\n=GSCx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG3PNgiT1jeOV9nK8eprhJUVVHeXbLWXHLlDUKh7JRYyAiEAg1MlYn9rn0OH97f7VJ1/mtGiyymb3jqv+KksodMJZSQ="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.6.4-insiders-1611829384.0_1611829422505_0.8869671928658478"},"_hasShrinkwrap":false},"0.7.1-insiders-1623221784.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.1-insiders-1623221784.0","description":"TypeScript plugin for Vue","main":"lib/index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./lib/index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.1-insiders-1623221784.0","@vuedx/compiler-sfc":"0.7.1-insiders-1623221784.0","@vuedx/projectconfig":"0.7.1-insiders-1623221784.0","@vuedx/shared":"0.7.1-insiders-1623221784.0","@vuedx/template-ast-types":"0.7.1-insiders-1623221784.0","@vuedx/vue-virtual-textdocument":"0.7.1-insiders-1623221784.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.1-insiders-1623221784.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-s/TkoXGQ76nSewMb+ahWOyvnWTe60/WnpkvL+jfkgiLU/pe7xaSkGobb2hxxIGxcxXAqcqulygXaYZQgpGfDtg==","shasum":"88eb9a93707bbfc58c15814cc37fab8b950162d5","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.1-insiders-1623221784.0.tgz","fileCount":7,"unpackedSize":1577706,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwGZBCRA9TVsSAnZWagAAbFgP/3y4vfizHR+uGMxdJoEd\nerDq50YybsLSOVm6+UxghZk9ZKrsDqjZbqdKSVlS2tVIEgPIjGYDm/IMqpVH\nxzncbX3gc6KHi8bu6vwtkopVndHE1uN79l3CNZg4ZDB/JM9A2GNAJ3QYbNcj\nw4meBC9tzKDE7ZiMqjxIgwgqVIxLVRsP11C5ZlNNm3FaJQnzvgmdn2Naak2l\nZQ+xInwa6Xj424tFKv5X2JfWtZSFgaCj2D1lcHOoU0MoJrdIthdLohKHKh4t\nkXyB7eoB5Qzdo3tyj3IapmdabqOcQGULQIE9namjoFt2fMk9lsU9K6248Pcd\nW/tanZGMuSm7DwI6g5nYpfIQV7YanEcH0dWsh4dasKCyAK9dEgQXKyZJjnxy\nf0ImqmWjBo0FqqaApRQsXd34gJiJ1kxJNUSnHrDlpA4G547PFM4wSUoEBSZY\nc91k3LOkxmSbmg2COFgYZyJj2MPSrcbgEuzpD7gngT0SmLyox3KgH+9PUM6e\nJXjQNMi5zI2FA4eot4NkDhaZM4s5o3wH1vJ9V3Boggurh0SIY1nNODZN7kIt\nsZN8SGl6ZxZS0MjsHhKWtezKNSPvplvZsylxLR8WEhXt8r3ELEeebOqiOME0\nk++M4pw5PrnfPP+ws/33TCfNTpn7exb83m8dCUQNQH/EXxaZyweMWq8A2wV7\noecE\r\n=mVrO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDH5lesDaitzNlQkLvelx+k6/qowV6JqMdpM/q1azULbgIhAPIH0dJJu4xxHtUod7ljs2Szum74mzaXb5dCh8l4Cx1y"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.1-insiders-1623221784.0_1623221825570_0.970900542823093"},"_hasShrinkwrap":false},"0.7.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.0","description":"TypeScript plugin for Vue","main":"lib/index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./lib/index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.0","@vuedx/compiler-sfc":"0.7.0","@vuedx/projectconfig":"0.7.0","@vuedx/shared":"0.7.0","@vuedx/template-ast-types":"0.7.0","@vuedx/vue-virtual-textdocument":"0.7.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.7.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-VCux7QSltqWjCjgbZKDjm8J7j2QOHcXZfbNYYIwZTy91eOpmCR0EybHAoQ2hXYcMhAEpmQvOXXmfd+2nDIK7Bw==","shasum":"bc909318936cfa010ac1fec9ded847191d51c8dd","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.0.tgz","fileCount":7,"unpackedSize":1577552,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwGaACRA9TVsSAnZWagAAldgP/j/xiqpfWI1dNVADYNhE\n5OXFyAzVnX1Qks7xt0r/DUIuRhAP5bDsAEoENld9IFNGh+FLYfpw1/vmNHuU\n4P58YMM6m6R/LW9UYMOEk07XE1ElqSi8KIRIDh1voO4+pLV4yT7MiDZF4ceG\nEMpQh4MExSs8DkO8OBKt8Z3cDhjb6jrD22d5RlkIuxP45kNmdkIv+kD6mgTO\n5TthT1GjsnFvusoj1uA9jFdhzo8e3t4XxwX5zS52ywADUQR36JRHPo+iyOpW\n6sAGX3krZPVAJLE1J3kSd88LbFaXafZlBZL35eYkgvbywpHk48p0WE1vRyFb\n0kYB3tQZYeRdqohDJR/lX5cPc0GxoIjUbioUpGTUjrdl1cVrDtAsCH2kWVEY\nDlWDC10UHLGX5qNQvgJrnQLnENCXrl+tG+/ZogFH3Znd5hqXJulCmaL8v609\nF6G5fjA6MXUHcQd+rfxGVQ916r9J8Lro5NLeG9iv5PxOdqhkn/76WNNtWLZO\nZe72GQaM7sVoO09W0u264INwcm56U6zfPyrIJIQ1H1Mo+Cwqzo1K3CoJQd/R\nPBFnK3o+ZQzwapoEsgNSrQQsGGOK+0lJoHQAgCV1eTcBHWlPeeqfyHw32qTu\nBydBUCDUmAciaMHtphvOeqWLXlv5y8pSiDR4KLNyOA3Titd6bE0VFrdF8lMQ\nQ5pP\r\n=q2BK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB/HYUSChngjxmeCTLhTm2JoU4jCYrygbkf1wRhoWomTAiBcyg31pD2+qa7LYdkOLDffM3jTGXJriSJ4X60oXv66og=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.0_1623221888226_0.222886233177354"},"_hasShrinkwrap":false},"0.7.1":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.1","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.1","@vuedx/compiler-sfc":"0.7.0","@vuedx/projectconfig":"0.7.0","@vuedx/shared":"0.7.1","@vuedx/template-ast-types":"0.7.0","@vuedx/vue-virtual-textdocument":"0.7.1","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.7.1","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-8HikRtUEpb9OvZ99rjN8mRWlya0kPCXA8NzFjkuFRQBkwIqy17B4S95kbOA00h0cwnl7wMFdkPN42LOH4DKmaQ==","shasum":"34a6183f3776d99e69d1bf3cb05b6b1770d48d42","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.1.tgz","fileCount":7,"unpackedSize":1036404,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwHGXCRA9TVsSAnZWagAAsCsP/2qTSFFmTV/uhxtZYpIZ\nAsSxFAd9GJ4QO8mfuEsoueXdtQaASswqWe009SlygQifQuD2Vf2Txk1sl180\ncJIdeRVy3KQOo4Y252qtcWcIk4qu1/Y+gDyrbDUR7cFwA7yvkwvxPjClBb24\npJHGOm4hohX0Ii1KUaQ+lG3fjyzW2bOqs24Qkv8GYl6NFrJp3zIEmbuGL7cZ\nQv+7rLfvEKzKbi2hkyAX3wZ9y9P4iwtbO0nlBFPJIjJNMKOZLyhbpNxNbGAw\nYWtLi8d9I2FYPphnD2CsvN7+U7fcdyzbR4dvTYM2fiXoKROUS7zIkmWI6HyA\nyWCt3R7TjahKud7BjKwq9nfGhyFu+M58civPsztCZx06EXL6FGuuWLv8pBXu\n0ywxjhiq0NZMWzEshkxiDaqDwqiiztlnMWnKzP0DrNsJ2L86LPi+xPerjg67\n3ihZjD/m5tN5vcUzCE7LGxCyYAmefyKVgG27B1Fu2S2PCryKU1ZL4jgclHSH\n4xJE1VH0xI8+eZLh3bqKHK5t2+rJC7aczKNXdVrGucPGBFV+CpkOm7I6EA+b\nrdRZ0roGSZe8Xo0vhcwngeAeQp6H4qjGWpstTirNlXJSA4k8PmsvqDTP4mX4\nFTW1aG5M9uEBMqeJ4eZQ64zgeGgp8szZ67MY8o8GGxADSGq1EbiRxk9Tetv7\nW/x2\r\n=P7fW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF+JvaAoj1rif9F79ZXI9tAXO6ke7L3SM8poErqrUi3zAiEAxhqg3aF4/HmVLW91ijc+jERi60IsJ7aKYNHTWyLEr2k="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.1_1623224727769_0.7739806177997297"},"_hasShrinkwrap":false},"0.7.2-insiders-1623224804.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.2-insiders-1623224804.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.2-insiders-1623224804.0","@vuedx/compiler-sfc":"0.7.1-insiders-1623224804.0","@vuedx/projectconfig":"0.7.1-insiders-1623224804.0","@vuedx/shared":"0.7.2-insiders-1623224804.0","@vuedx/template-ast-types":"0.7.1-insiders-1623224804.0","@vuedx/vue-virtual-textdocument":"0.7.2-insiders-1623224804.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.2-insiders-1623224804.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-VY9B041c4bR/n1aSpaYJWLKC2DCrkMLk9OaEeYQw2YMjJ+zl0bcWI6Gdx6Q7H77rA7OQf3WO5zzC61kL5BzL/Q==","shasum":"b346bea757130a597a3336362d0241646e89f41f","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.2-insiders-1623224804.0.tgz","fileCount":7,"unpackedSize":1036558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwHIICRA9TVsSAnZWagAAd1QP/3LoO95UsSz8WITs2gJd\ninbgsWKljjECZt3Ffh5P9jE2XacSJIhe9AKNYqqS0ZOminJbmu/aGzGxyZ6s\nahy+KXFN7QX1boZbXOujuv9oi9rzPp9DdYRJ3SMaPKAMN2Vz0o5hKVEIqw6l\n+YLT6bJMgVux4B6m+BtpnFpIuyK1X/pWpImzp2Cj3geKOQKC9usr2SgBc3wE\ngqoq46fyxtTOifYbMM9ykZhJ/tGVsu5au/70b7CTNBZOJbwj+LAJO0lZFxpq\nqbXtOx8TPyptkmKECDf0H2q6qlLGcaSV6tTU0eXnaGUMVLZdKRtQFBPS6/9t\nVwJp1CtJT51138RyduHPRJFulC5lDRpKn0Jm1UQIfiUv8F4Eaf7BHumE8D/U\n5m/hm7bTCja6Js5gWp1Sk+XmSYWzIEQliAKOlqM3AiCF0gm+p/umjRyeA98p\nY93T/UAOVzhKMhcyDcCZomu9+3memrBOEhHHJrs6IymlbvT3wog1XEViTUYH\nYQeg2x3k4stmLKOJi50W2pB+8EQMdRex90U5ff3/ybyQ/HWyyH85/bDi6D+n\nS+1mOqCfvpaM8AQ58ICQ2l1p7fc2w4jtMSyDVapUBgmmkjCvaxl1nkXfW6ge\nBxuhHf84BXfK0z3V0mEfDS/DcMwKTwSDlGbdeJW6U9x5SMcWAwCSw/M1fQkr\ng1M1\r\n=noUW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBdxny3rmur4IkBNMP890VFBiL55Acci6fYKdYAVZ4XPAiA9uAKeL5cogu7wiFzc7mCC4JvxxzOp3akSuWjaibMPEA=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.2-insiders-1623224804.0_1623224839702_0.9795239477475739"},"_hasShrinkwrap":false},"0.7.2":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.2","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.2","@vuedx/compiler-sfc":"0.7.0","@vuedx/projectconfig":"0.7.0","@vuedx/shared":"0.7.1","@vuedx/template-ast-types":"0.7.0","@vuedx/vue-virtual-textdocument":"0.7.2","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.7.2","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-96aWk2WOkkxD/84mWWMUgLzs/hbpxMQ6S3LA7tNDwtULkziT9MZc/FG2Zk6BaBG2IOJUAv5EVOlxKEeUdQE+MQ==","shasum":"15a37833d46eff2454cc4962f745fc8901451ab7","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.2.tgz","fileCount":7,"unpackedSize":1036404,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwQRECRA9TVsSAnZWagAAkHQP/12agWVeRnKQ9Y4ZK7j+\nx7DnOwUUtmPzaZM9TtwJDQ6ChnVkwLPf0rk/JFawZQdMO5An0g60+9nvly1L\n9wycHPby/8IfGEfUCuIKxjQ8v9++b/OpCOPMcxnqXeznCZ5btvd5zXk4wZPK\nH+i53kgNsTV+GVACJdnVUBZvWcADg+U0xzUHbQ+qWyZFsKclcpKqS9gJFscr\n0ph59l6Z8fkT1C78Up42XdqgB9DNM3eLmydH0nK7VyV+eJYwL6F1u9AgZVEU\nZr1LvU45rwHCeExlpJ7LmfVj/yhlL6jhK68kpafMeh6hj8HC2NZvafTLJAcD\nfKg1zfQPS6uOkafnpP+uYYwINMseLfkhq9u3hD7BV5Wsaxckxw5nxGgZH9e7\n4bb9P04O0U5hauYmb04Uo09vdsa7QYf+E96dwCW0cjWztWZ+E1ZyNWHk+jiR\nFkaHcB0zX5fu3jzx1qcGkiPVM4JpOtNJnB9a/un7VG5UmQwRSlUrWFrnYFcI\nELofHIhqvcBQZxRroDjoU+EVj/MEjpz19eHy6eC2OUBkuUa73gxf4HIa5etR\nalQzOE328EI98m8nJn4A9RNGm8Y4nrNqUTPHkU2BV58tJGYnult05CUFDOER\nc9IGyDvfhxtFucTTt4SvCdtH+j59VmEpyETpx4AOui7BZZDPfR+gD7Pn4ZA+\nBP/f\r\n=WjhP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIClcHx75/Pr+IYmojXtUtN6E2+mCDL5IckYdQLA5gXxCAiEA+ILyf8GFCaJ8opYAF++W/Z8bvk5JXQ9rHzt2lwiC+Gk="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.2_1623262275906_0.634965079445011"},"_hasShrinkwrap":false},"0.7.3-insiders-1623262375.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.3-insiders-1623262375.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.3-insiders-1623262375.0","@vuedx/compiler-sfc":"0.7.1-insiders-1623262375.0","@vuedx/projectconfig":"0.7.1-insiders-1623262375.0","@vuedx/shared":"0.7.2-insiders-1623262375.0","@vuedx/template-ast-types":"0.7.1-insiders-1623262375.0","@vuedx/vue-virtual-textdocument":"0.7.3-insiders-1623262375.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.3-insiders-1623262375.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-tKoXEg/+zEaZyhP78bHtt0nKVabSD4rRc0h6uHriLZLbAgu2d7zmsA7u6c/DSwra5KvIFb4LR+Xnk9e9pzRx4Q==","shasum":"9d41aeb3abc95efffda2902239dccd12e9346103","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.3-insiders-1623262375.0.tgz","fileCount":7,"unpackedSize":1036558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwQTKCRA9TVsSAnZWagAAMjMP/3iq1Nm+zxPT1bZeMSm9\naNcDOQCyNGQ5/yCB0kdFqLmhAfVMG+zXa99VUN80/uf22EVjpjakqCCn6naK\nW43qsE4yjj6/4d+w2bbSNIu23XlWpnk/Rhi8SCEqgYLZqv3OXS82rd7dUuBt\nqju3bonC/w9H+ag8/dATpXnOr3mdiOPNH0/Y/r5sBaEUTg+En8jwA1pCYW7O\nJsIq8nTwErodfi+Gn6A+CgITEliRqx9p9l9++JFx+Cs2qiJNRs5Q2aJbz0Pe\ntZoKNgE9/aUZzoEb1744MDyakfWw3CEidN7PM2bL+HP6ZHoekP/4j68b/+Kc\n8QIZmwdCusGLsl3EUMUQSiJxcXGCsl10YS2gbHtveSBqXYOWj4lI7NP6wSzR\n5uZQFq4Wd8weAQ6Yf2teIh5aUgL4tMHYzyZQZLlWdJcD3MtOgJ0u+j8sji3x\nh4cz12uzTGAeLpfbqEV4rtqvUhRBkpLr2y5m99f0NeR8mEv1/O2MwmHs/pJX\nGBjdIWpbdzqAm5JjiU9mL6JdYIr1SpJ1PFcMLFXovyv7Xy7e2qaEsOGRTBkn\nx5Uf8H6VJ7NcAhsO4EGrDWCXiSkfnP5yiIo2FS6UM2CYtNHwhEuJNSm6Vof6\n+L9k03CkMOrelJ89BLdzb2Gwf0Lct+Jgoke87MYyEJcXFaIXO5VlLFFc+D3F\nKXe/\r\n=I850\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDl5lW6YFgQoERL3Uk2mN0K12ZGrTw7QRqzz+9N7WgeUAiBBcipNGKZeAY3OcoZGiEZB7b4zOsSmeujWZ4DaDUflHQ=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.3-insiders-1623262375.0_1623262410421_0.1732693750954808"},"_hasShrinkwrap":false},"0.7.3-insiders-1623383290.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.3-insiders-1623383290.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.3-insiders-1623383290.0","@vuedx/compiler-sfc":"0.7.1-insiders-1623383290.0","@vuedx/projectconfig":"0.7.1-insiders-1623383290.0","@vuedx/shared":"0.7.2-insiders-1623383290.0","@vuedx/template-ast-types":"0.7.1-insiders-1623383290.0","@vuedx/vue-virtual-textdocument":"0.7.3-insiders-1623383290.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.3-insiders-1623383290.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-eydu64a+EmkYCHDEDnl3OXkcOzZg+05ICyN77o6TqSHfdIofeCx4d8ub9M3RYwx3m1JulwatGCmKNFHaf+3gzw==","shasum":"e41e1ab6653521bd1c1f627c9b36c39a1126c1ab","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.3-insiders-1623383290.0.tgz","fileCount":7,"unpackedSize":1036558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwt0iCRA9TVsSAnZWagAAZNcP/Al9LYIHthgcLbk09Atj\n2oFZDI8ULrvj50OIg+W91HGkziKfJ1hova/vmd0sDBfH/P+UXEg8c0RxJBXr\nJCyWhrsb6PZrRiN6TrhjtN+HS2AbL48sIcakKUSzMAimO8DpdZSBLdXDanmL\nQMkSdf8cNvU5E2yixpmnJMZEUR1OZzD5zCrCFkZ+JqgusHU05UZXuoMlRLeh\nrNF5zIRNW99YgV7b7SfX2hRUAMyVts1lnsBKnKgct+Y9OUttwfVZIjYpCQRV\n8pIybQJ8fhFxavTttOzOuA8ZZ4dE/oOi0bEb77Oi6wyW8Cq6ikbXbwcv+JV8\nEn87FJg9bsCZQGvfQZWKLDvAdt1c9Wk9/9MOiTbcw+05qRx+mwe8siLUGrL3\nSj3YKeIaMrY0PuFPLCHM/8/vVqJ944LA+pP28aMJ7XKxDOnE+T3w0avrn3U8\nHBPRywexhAWXXcQY/BGLLwiQGkiVNw0hEMZH2qL+Wvjr0dagMpcGUCABnkHq\n9raqfuOIxjgVMm2TTAfCLbWaO02OfAHP6g5sVqXShlIlVqXUc7GEwvyT3FIq\nA2M3886zUsKXD0XSfu5L7HJ6qWsB3WX9+o/09J2p5cvsRTZ3rIJjYFIPJ6r4\nZpdvcIcIXOoTiHSjIC6pTzhBk8pLgTTO0UBUbY+l5U/tTtveQOEF3j7yMcEn\nkWzv\r\n=W4r6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC6rbu8WRDid/K34ZPHy83idwQxowaxzj42HMk9NPA3KgIgUOKRh814Lv1CjRHWEivLM2iTMhz9ZG1eiBeV561DtQ0="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.3-insiders-1623383290.0_1623383330443_0.7728574767812975"},"_hasShrinkwrap":false},"0.7.3-insiders-1623383952.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.3-insiders-1623383952.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.3-insiders-1623383952.0","@vuedx/compiler-sfc":"0.7.1-insiders-1623383952.0","@vuedx/projectconfig":"0.7.1-insiders-1623383952.0","@vuedx/shared":"0.7.2-insiders-1623383952.0","@vuedx/template-ast-types":"0.7.1-insiders-1623383952.0","@vuedx/vue-virtual-textdocument":"0.7.3-insiders-1623383952.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.3-insiders-1623383952.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-otDJiidyjVX/UKcTmdQ7yGjajkSFhlXPiK5uOWQ8NOb4/RRhWsBOw4hVlbphDxWA5CcAEbu9x3/d1qpPFmj4MQ==","shasum":"513b04cb65e636cdea304bb5d803bb7da11847a2","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.3-insiders-1623383952.0.tgz","fileCount":7,"unpackedSize":1036558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwuASCRA9TVsSAnZWagAATyAP/i1jjaqmOthcQmFBPbLH\n040eJ7zh4yeX1F65nBPcuhrXsTVQogaq/6qmjY5bToY+9AQ8uP2PSxYRgkdA\n/1tPW/2dC0DEsJqxH32UdLl9HgauWkvXilFpWhVoGdo2XQXYFAFsPVQGAWqQ\nu542wd/PahL5/XHgd+PHoAOTi/f3E6oqZhgGMJ/raHtPaoGUQy/zc1jNNCDu\nVKfB3PgV//27ie9uZAwgGfQ6dWIc+ICcV9u7IhSDyrq8e1Q5t8WUtfoDvKHF\nHAlMRwP05pSqBYfljvSkg8oIwZ0cZH8V1h7fcfLCD0lbCYA/yuq0KFfwMFUJ\n2h+HF+sVEYmoOXlBzk1vVjp0VKDBReO59hKDFUF5dMB0o26FrjDLtoL0k35x\nfR80M/02nGidpl4sQ7WhG3f3jC9mLLQoHP/oZm1MylQgvNzB7KdKmzo4fSrE\n8nJgaIvukrQrxsr2oOZ4fJsegG3vI2XTn7fPEaGDCNKzKm7+UZylBWCY90Tv\nADmn8fcmEJFnUSTQhmzJoE9CyY0twTUfgVfaDAJgWLlWmW2jLkuPJmr45Z4K\nNQeLK5hI16/EX4DkV8ta273f+f5KygcR0ADFh+PNhGV6NWmrJeYF4238X7mi\nODu0PowAOsYVI5hJ6EeCf/ARG78HI8MuIFHsFZKfqQjHmZ/UxGOV7ZBzB73M\nlbH5\r\n=BGc1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICLIkvLPjrESf95nXQzz5VnWucbf2NKOtLgS1YALyCrvAiEAorHVy6YLx+kFUZykCilxIpKSVRClGeDJG5jN1tDcm28="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.3-insiders-1623383952.0_1623384082139_0.7086720334871488"},"_hasShrinkwrap":false},"0.7.3-insiders-1623384696.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.3-insiders-1623384696.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","exports":{"require":"./index.js","import":"./lib/index.mjs"},"publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.3-insiders-1623384696.0","@vuedx/compiler-sfc":"0.7.1-insiders-1623384696.0","@vuedx/projectconfig":"0.7.1-insiders-1623384696.0","@vuedx/shared":"0.7.2-insiders-1623384696.0","@vuedx/template-ast-types":"0.7.1-insiders-1623384696.0","@vuedx/vue-virtual-textdocument":"0.7.3-insiders-1623384696.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.3-insiders-1623384696.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-b2/JK3uLJZKJfCjpLzLN2M8ehK2bI+MDrBNWvrDzcuEcQtBJLzUNqU7cINZPbxFBrBYK0jrmwIs3muoXGphqbw==","shasum":"171683dadf027a7ed696e11a59e09fcc83599556","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.3-insiders-1623384696.0.tgz","fileCount":7,"unpackedSize":1036558,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwuKhCRA9TVsSAnZWagAA6tIQAI35jhewVPPK1kO6ZjwT\nWnhz8c8gd1glh9IPRh3zekliiaby1/yFndmWHcaORl+p/4C+A1E90GzkApIa\nrMv5+yTKbYjpMlSENPN8yqgDrkXvdvWs8IAE6Bo9jqWJuWqqVMwjv0U6SU4t\nKjl59ggfKcK0eAVFsKFT9sveK3LymN/WjDYLSBxiODuBIgbczjqrB/BzlP83\nhB5ZIngGYtLnkGdMmfUu1AwhmP3pJ+URpJeuube91yNwaPknifi3r58l/i+s\nMIttNGqut0UwigAFMpcaVRzYHvjYppOBeegQL6/KYKbqbfVAAFPhth9eWTOB\nzvq+QGJbJhTTvg5rbBGnVxYzIz/wtutSyDukHlfnE4NA7N+kSGTc0tSFJ6ut\nOe00168hb8Q3RiZDgDoWYU7wOpxoEkSGCgaX3DtUtRsyfPphymw7dpiASwj4\nLZrzPE0CEPORYE/WHwk8Sbh2CUoD/kJfZ6Ua7JehuzIkiQ27zeg7E3JxdrHz\nAW8bkK6GEjI9Ng5R2CDHxTq4y/Nb7c5cbhIThJyzaq7f8YkPROOAbH5gHq3+\n7sRdokvsr/faiG4kc/Z489XHUSpo6AEvsl5hnRENezNRMvhxmWuWE1TqqgZ6\nxqyLVoKwKgj9+6yMnQlJBXzvst8BgoHZXDdzxttsXt5LOWnoDTl+xiO+WZGB\nsyUH\r\n=Y35C\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICD0BTXgb4TZXCmqsgN92NEbWPzyXSrtejfzAqXTsEyxAiBHV4vjesr2sUjbIFMEumh6vvRyPhbGddTRFjpm/xh/bA=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.3-insiders-1623384696.0_1623384737188_0.42271891885749024"},"_hasShrinkwrap":false},"0.7.3":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.3","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.3","@vuedx/compiler-sfc":"0.7.1","@vuedx/projectconfig":"0.7.1","@vuedx/shared":"0.7.2","@vuedx/template-ast-types":"0.7.1","@vuedx/vue-virtual-textdocument":"0.7.3","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.7.3","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-pc4gw5vfRWUQFIQlvqp/UYFdyIZmARPlGx1PVopI0cbuPM/WEwdFlpoYFnuffKr8fPPENbXNzbv3IP5Nf0kVRw==","shasum":"f7340ce7f18c20bfd0b7ef29010dfca00b6886a9","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.3.tgz","fileCount":7,"unpackedSize":1036329,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwuxsCRA9TVsSAnZWagAA0eMP/1M42SiipV+arUOO7UFk\n31XYaJHfCLLf399ShO+cMIT5FNS24Eu5/ASM+ihLtnMN0sRl/RyFdw7qb+zz\nm8KdqtPD8/ffrpZSaUKge1tulcEl4FFO6QkJCfS0YpCbs1ky9PshZ02J/89d\nRhb5n/c/90L4FX1uGTG2TZ/MlWyZSe0ZWQHwe55O5bDOFL4aTHkNnFi69zg+\nloFKFi65yxPUGTN/HD4gYaFk6BEDcyx78sdmDY54FjlcUoYOMhJfzWNEABF5\nXCpFAZBMpoqDPVwyIcQaA1R63KQooB9G9v5XEsfw7vaaszsKVE/mJHkVdHoG\nwyDctLUxZ2cmWULnfic8Cntnx60fyZp+xx3zTLA3590JpyErk2tK7yssJmZS\n7NXNosaKVvpnrLQc9HSiTLLOSUOGCZoQzRZ6smZrqzC4s64Eja7Qwx8TZ4Fn\nXA1HPfhWvB+sK6MqkZt7EA1E8c+d7QT9BvNvnJbRI9lTXU4+T2Hr59kb9zqk\nHoMqhO6tepHHiZtxdQHs2jYW98/GlmEJIrtQjdTKjkAFlyKJkYoZf4EvjfsR\nysOb05k+k55flaskrZCuKoB3oeun9ebhpRQGXp7L9XfZfSHVeOwbrn1gWGEc\n6HrGSxeckVyo4FGRlIrLOP2Juxc3c9a2yh2z1qgJ5BY3BxKQkQovPjXMlynu\nVMAw\r\n=vFba\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCLIS65Rp3InBMRw0Ou75FKcwUZZ96pNAvDGEymx9mj4gIgW1o0fRpvLoVPuPT+LCVkPz+ekgm6jBdLAQ/kbwFRsj4="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.3_1623387244212_0.04673351291795935"},"_hasShrinkwrap":false},"0.7.4-insiders-1623387961.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.4-insiders-1623387961.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.4-insiders-1623387961.0","@vuedx/compiler-sfc":"0.7.2-insiders-1623387961.0","@vuedx/projectconfig":"0.7.2-insiders-1623387961.0","@vuedx/shared":"0.7.3-insiders-1623387961.0","@vuedx/template-ast-types":"0.7.2-insiders-1623387961.0","@vuedx/vue-virtual-textdocument":"0.7.4-insiders-1623387961.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.4-insiders-1623387961.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-VbhRoDEI/jKZzxbM/XNp9nP9nqY+kH2769R23zCD4GiYrkbxlOjk6fxuvs7dc15k3tFvBa1MNl5m7K/7DYj5eA==","shasum":"731e19744d2bd3d49bacc379d52c39fc7a4af621","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.4-insiders-1623387961.0.tgz","fileCount":7,"unpackedSize":1036483,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwu9eCRA9TVsSAnZWagAANrUP/069pl20qj/vEU27dTzs\nZZsXZCZCKbI0X4jPVvRpz1WHiubo0mlgIlAxnNFD43ajlDlhOEXGx1we4qA1\nTyFHoZjC8MTXOQVWWvp2i4+BRHo4shKWZM3yhMssrmMLIStDkyc4EzYDbt/y\nNXSciYl8fBNx8OBdPdlGRv+qeRMljJOt3yCGr2bdk3BaQx1RwDgkbqAw+4XW\nmze1feGu8Iji41ZPbuyJZCGp2grbx5hPsZTXyaBYUVuUUJpqoPPRU+2nNvDi\nEtBoi+L5H4Xr2rksBVbwJSzCC5+JR+KbN5TxNMlvGKm+ydycpauOf7/wd9Pd\nQurHXhh7toIdYFIiqm59n1xpdjmXsrNOdef1HToJ6k6KlX5Ec8m6XS39R7ZQ\nAy+7pwXZYptSzWniFcq7BixYnfmeosOjG3KnXosV913uQ5nK3lCj2kKd+t6L\nb/YB6lJFAah+Q2F0rsmXDDcK8VRTm32tLyezVkXHSP/WupvAO5Vhq1a9r3VR\nDD+7qNQjGRkC6mg5rrQLC94JN9CDWAoufjUyxY/dDHW/3NgKvZGZSB6oCHYl\ngLLtrOHrIG62tFsdcYJGqW/G4HKxq+sRES29ua0AFspNjvQmrxADOLqhmZhJ\n1sE28OtO6TJwJR3diFh9q7TqGSikCS8Maq/E/c0SCJw+Rf6j6fFPsuzisfV4\nyiR7\r\n=Sblj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDLIOR7CEMMTHdW2EzG7OXd1wZPMUwa+GL6T/Fh0z+XYAiBV3jmqy6zjoUYi5oDUn4o9+tzQe8wAWWrx7408Wp1luQ=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.4-insiders-1623387961.0_1623387998492_0.15617742528087497"},"_hasShrinkwrap":false},"0.7.5-insiders-1623390917.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-insiders-1623390917.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.5-insiders-1623390917.0","@vuedx/compiler-sfc":"0.7.2-insiders-1623390917.0","@vuedx/projectconfig":"0.7.2-insiders-1623390917.0","@vuedx/shared":"0.7.4-insiders-1623390917.0","@vuedx/template-ast-types":"0.7.3-insiders-1623390917.0","@vuedx/vue-virtual-textdocument":"0.7.5-insiders-1623390917.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.5-insiders-1623390917.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-7mxa2uN3EzLvHafYyOeqtIf1vhbsVz5tKiTqYIeDo8Bep0NvcSD++A4vub306DVgiV13k3BxPFcaoHOlOOOEWg==","shasum":"67027d99ca102879f7e6dffa706d614938631018","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-insiders-1623390917.0.tgz","fileCount":7,"unpackedSize":1036483,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwvroCRA9TVsSAnZWagAAC5sP/00KXABnuxG+ku5SC22h\nlLzHssBZ9ZWi9ODbGD4KeP2rYBaFLd1K6Z/0CDhIPFt/VxJIkLed/dZbL/BK\njZQoXiJvAeWt9zO4K5i71CrPVqs0GG5pDGXFkU3BX2uswRJvpA59Dg5iaHvo\n0Fe5TOIY9s4NY9vv9JCNXOGJ98OTH7prL4mM43/qJSKu14TY3XVsMnJKDjxk\n3+wkqbWMa8TLj67oHeJ6+6KYnZh0BYpNpMFiTfsA8BJL7atu4hwnfEI0/ani\nWR8Sw5mkcsWSz54vd3/0hdPCJp65to4U9IwiQhr8v8Yb4nLqaBe1c18bNhuO\ncJ3PBqA+0rgKzN+MoA+iUjWXDkFL503Quv5ZCmVE3Qi5L+iGtJzFsqeymU0K\nbuzTgevbykzxsAdSN/2op1v1Scnj00+rWfWLjvQdSWrfIPHhIAUoSJdXbLT0\nwnGjNyBgnkCgSflA16WXDKwAOB8kbnzUwGRu1OTMp3p34wdxk0U8wYkiVJKD\nqLKY4rQTsj1q8RiwlHpz71JXSr4nuKetAjPsBjPnCj8gru8OpDukEbMZ8q2n\nvjCNgggy04UOgm6Zz6luTxf5qoP3mir0ecMVii/lXzbWV7X9xB+iVTosWCXG\nBmfLXknxLcrDvl9MS/y687+4mo7JwdX8vB8MDestKczrfmOLOiSQc4VDrVva\n7m2O\r\n=nkkC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHum3/eLxoIbdMqAp0iYV99f06ni0ypsZ34F+v7Is3l7AiEA0Far/Xi7IylJhC6kOcCThKe1FbXwpngK+okoG2YJDTg="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-insiders-1623390917.0_1623390952718_0.03259154147626253"},"_hasShrinkwrap":false},"0.7.4":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.4","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.4","@vuedx/compiler-sfc":"0.7.1","@vuedx/projectconfig":"0.7.1","@vuedx/shared":"0.7.3","@vuedx/template-ast-types":"0.7.2","@vuedx/vue-virtual-textdocument":"0.7.4","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"_id":"@vuedx/typescript-plugin-vue@0.7.4","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-SVA5UaQYPfyJMSLvOab465mzR4iZnLPqormv78Y9SKbKhS6O09ZgyPM9EBwLYl9ySQQqDyAKBn4H0pYeL3ydoQ==","shasum":"9953251a26ea6f99f6a77c00848072654b4b2038","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.4.tgz","fileCount":7,"unpackedSize":1036329,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwvx9CRA9TVsSAnZWagAA3S0P/3bNOKm5RgqqKL7qMvmO\n3coaYdijtYixueriCIAwg8kQEbbWBVVAvDZnlKkmLCrIvX6HxIZ5tIJhRNia\n2FBQcmHw6vRL7V6d2ATKjB5PuxnnEwFUgGujUUZpvKRDKshN7+DftIMxdRUT\nvZyic6j+5wnexTLb5Ubm0gmwzzG7/AHQPxf1269I8Bpss/a4f/iUnDMrTWzv\n92aCum5hrHeruRkmy+YHoxKYl1SldpCoj1V7NQsfSbO3rH80Je7pB3mY/lFn\nlPQmuerZm8Y1hUzfv3hQMK3b3BBg88dVgoe7QrLwKrn8ismopaOyCnFOuk5G\nrs7UwbJhn/3aFPwd/CDWZe9SDQIwSwa2H2J8ye4G90wiCBBUPz+MiJuiUDi6\nBnpV+vFSbaaoYWAfp4fdGcPPblvcfhJTcJJJPmXHbbZeY0UHjFvXDxJ0X1GE\nkx63H7834ERS1J8OwcdZVFLnX5qbj5hnu2Rz4LkF7WCnM5A8KVkNH60JeKaX\nEr6ORW/R+ssDxWISNcTxHpo+G94gIIrsFVdhbsI1XBlxfEiGeabZVCiECgqB\no6dQHU8rIl31W1lZC2GxORUTeF0NLZre7YQT4BcfXuZn7VhB2kwMjyp8hUqF\nnvtuduoJ144mlKCwsxz/DsJy/lljEhConBNq3AnPKz3tYML9ueG7smzWRDKq\neLYe\r\n=w0hg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDuPc6NYdQ5vVkieBcx/SUgdxNxTQalO14Fb5eZqUGCuAIgFPBEdvgiRWbe4GFxRRBDLxSBE7NWCr2OHxsvlrCwZf4="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.4_1623391357174_0.5872544935026114"},"_hasShrinkwrap":false},"0.7.5-insiders-1623394946.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-insiders-1623394946.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.5-insiders-1623394946.0","@vuedx/compiler-sfc":"0.7.2-insiders-1623394946.0","@vuedx/projectconfig":"0.7.2-insiders-1623394946.0","@vuedx/shared":"0.7.4-insiders-1623394946.0","@vuedx/template-ast-types":"0.7.3-insiders-1623394946.0","@vuedx/vue-virtual-textdocument":"0.7.5-insiders-1623394946.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.5-insiders-1623394946.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-BrMiqGr39ThAa1xumYVNp9SzONWjZ1XOKKIB3G7TfM113oNXfwNS6p4qiDEOhVoJeM+Bfhswon8SMGUiGBA4lw==","shasum":"ce1eae030930fb3bab295fd9a3a48e733fcd48c9","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-insiders-1623394946.0.tgz","fileCount":7,"unpackedSize":1036483,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwwqpCRA9TVsSAnZWagAAWNcQAJOPxSteQiACNlKjTsee\nd314UKppZh+acm5TOFVsANmxDso7Gks861lm0T1qEkFiB5jA3Ta3EeJUUi5c\nUeT38Mf8ZhOLKNy7aP/0jtXaBqJb52KYD6Il/qR52Mq1HEABKSWD4EQmXCjg\nb8aNyd+F2flzumc9vuTnbhTeRxsNxLsTB0ZRX8rEmrffVulWANNOTI5DTdHL\nuQ75iMMpV5M6TSSS+a6LTtOVx1j8+Vr1Wa38pQnTjT6SUOO3VmkHE5oRmwnh\n0/oJDbNVZe1Sv9dgxV7O7b3flkh8hdChw7utcZJPH1KhmQ5iXsuc4yDM18ZM\nxR+4tuSCIcEAOwvUgKo78TSQtwyIthA8fNy0EIbK5ej4yl2s3yLYZ0v+cdoD\noPT/VadxlN/QoxsecjYO70zMR7gvJ3TXnzxX9CORoJyg15cxJeGiIbhsW1IC\nTj35KUt3smWopXJYXUnJ4ph5kcV83P6wiClJ/ffoNxkjx83SFUj8S2ZcUm9L\npItSQd5TpRHSup665YvaZQIDNbTumYNN6KwOFEKq/r9Y8jhfw7FC6+ohrphs\nwomdcyIjVTJCGnF1411+N8O/fU73x57/230l0P9RCpR84fu9O+FoYdD5MnoM\ndpG4o1rHcVRycmlMSxjuAWn0J+i1Oq51gXTGlDSZjAQE5E0k6LXO2J7bkm7f\nFcUk\r\n=zTub\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCAd/my/s6nQO+iVcWcMkNZQ/lDUHlYdQ62G/337jeBdAIhAPq11fzWXzXYfZCrtlb/g/xO1kYhimyQux7yCbYgGuKX"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-insiders-1623394946.0_1623394985449_0.7283302539062095"},"_hasShrinkwrap":false},"0.7.5-insiders-1623402835.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-insiders-1623402835.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}],"types/jsx.d.ts":[{"format":"dts","file":"runtime/jsx.d.ts"}],"types/render.d.ts":[{"format":"dts","file":"runtime/render.d.ts"}],"types/vue2.d.ts":[{"format":"dts","file":"runtime/vue2.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/analyze":"0.7.5-insiders-1623402835.0","@vuedx/compiler-sfc":"0.7.2-insiders-1623402835.0","@vuedx/projectconfig":"0.7.2-insiders-1623402835.0","@vuedx/shared":"0.7.4-insiders-1623402835.0","@vuedx/template-ast-types":"0.7.3-insiders-1623402835.0","@vuedx/vue-virtual-textdocument":"0.7.5-insiders-1623402835.0","de-indent":"^1.0.2","json5":"^2.1.3","quick-lru":"^5.1.1","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.0.4","csstype":"^3.0.5","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.5-insiders-1623402835.0","_nodeVersion":"16.3.0","_npmVersion":"7.15.1","dist":{"integrity":"sha512-0dy89YZp37f06IKz5VUshu2W0vYiqtaPY0/Xl9sHu2fuvmpN9z4SHtYVsoHzCeOMeqx8hGHsNGvThjhXST/EIw==","shasum":"ba24593d16cbdf213d4a7f6e1cd6c994cb900a94","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-insiders-1623402835.0.tgz","fileCount":7,"unpackedSize":1036483,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwyl6CRA9TVsSAnZWagAAXdkP/0DaeD8NORpITYFUIy5t\n5/X1Z0tLO9MrJ7HBkcYir6tj+1gD5k+1d5CmuJkafrha5+Km4MBYitWYNhyF\nU0Ipe7Bya5m2cARhw4lzBoPREeY0CyrcpKqqe3XodxnpBKUx70JhycyV9Ffx\ngnRdRvYuVwVRiRMkPzl6QBuMwWNJ8JBrTUMgb4Pd7GjqF4DKIBPqj7WXvFTd\n+4DZLXHV+jKsFn8VghX27X+N5RLwqQvt+3IJlH1iA6c4t1uKppU6/YJmGOaW\nRJMYhE/nn3Ex0wrT0/ZWLvwhLV0XvimpMh3xA8tQ+V3tuYShIQKMueBBKa3C\nvvlL2APdW63OommBKJ76qwkmx0oxwApvLhb7M12MvFrpZTwyXs8Y2NAgcAr5\nsuZQEyxj8ENL3eAvgKnAfzP1YhXpHDssRsWtlEupRuYZCkuJi3GGwwieblpq\n2QPkidgsL1Yd/snis0+5UB7YQIxUsoP+61LsQ23qgrsGkZevMQHJF1J+seAx\nFXMQsi0Obf3cDizkAzXNVsQI7Z79w+3T6sszaJPzwjIy6kiz4Ss4JS6LpuU3\nQvBoVsml5skPnj4Bt3N9qqUjLwGD+wXPxhtdxXV/hHav8mP5dBZowl7O1jKf\nnKdDdFb6wIlzw0EII+uy0wXNvHFnpWcU/zOuCJ/GNu0EQ9Ek8LNo6Abl/cHb\nqATz\r\n=q4/r\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCFKpVuZ9RUMEZeom0oeoUF4LgjtAU0VmERQ66eD0c5gQIhAM8mwW28iewxBjWQ5eSsfF4T+6p4F1OJ6jV35dDxDkUz"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-insiders-1623402835.0_1623402873919_0.7775342919703991"},"_hasShrinkwrap":false},"0.7.5-insiders-1630600136.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-insiders-1630600136.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-insiders-1630600136.0","@vuedx/projectconfig":"0.7.2-insiders-1630600136.0","@vuedx/shared":"0.7.4-insiders-1630600136.0","@vuedx/template-ast-types":"0.7.3-insiders-1630600136.0","@vuedx/vue-languageservice":"0.0.1-insiders-1630600136.0","@vuedx/vue-virtual-textdocument":"0.7.5-insiders-1630600136.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.5-insiders-1630600136.0","_nodeVersion":"16.8.0","_npmVersion":"7.21.0","dist":{"integrity":"sha512-TP8ge0IvdaQA3CWpvErSB5otVEdrtVqpjl8y7e9GpBW5QfV1WjhYuCRqdcOZhYTKq2fJSJBBRg60gAjz1TIQYA==","shasum":"f7a5a880c8c0a947a45b7c8d60243016b4f80486","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-insiders-1630600136.0.tgz","fileCount":5,"unpackedSize":28042,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhMPvyCRA9TVsSAnZWagAAWiAP/2XK4AHWJS8WAbLRDt3Y\n9DTD4PNpX8D/YruQMmLoGcwhEZuQKpX5YJY6g2/dCRNRKTJAB2DJphXC3om+\nzMuq6y51JmLNBlQqLIc49naMCJHca7HsFuwcxiMqeLbNMbOa7WV0HrHIBmMg\nhFkSUr88lMCso5oCe/ohHMuxSI+68FXAW7xEeU6F4pDpfHW/g4rgis2+AdpQ\nL9mK2Qejctamon0XLUSovzGoYO6wOY5XQIqsofE3IwvSA5M36t6JmDF1a0J8\nbWIqz05Yk3+V/IJ87s4iUzgA7VgodK+hFlODYYL/ipHQu24OBiYUWsG/Biiq\n14hA4YhH3NbX25+D9nI6Pj6rXBEBjcJYovKwwYJRoCPW9xG1FSvSpHs01Rkw\nbaTZkkD7g6VUdf1fvlEElmNfNbjvXSkVQpdtBDEyGEwHBjRpiV2h8EhxjTBJ\nNuAR1tRsLowjq07HWnnF/qrAu8LXbvc7euCvhQvoLlMAL2U1DQnUIoQZ9r/M\nWkTSw7c/8H050j0okRHk4RiN+hjpQ3IzlPT81FkNwY9b5xlQe4n4utCyS3Kl\n3TVjLVbe6jUV5Y41GsvnDN1of0XTyzkZTNhIfjmosZf0yh6WoWxhnnLTyjUh\n5et55kWrlkcCj8SoM/rtd6ulvwgXMOxhY/aR9LaEhNrd4NYpX3UobyOd0WEP\nPMg3\r\n=N+fT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCFpNjoYByuoEzqlIgXKvnXIlU2ywiTj6oofjzDY01oNAIgbpk6bDxnzBXcWKrF3WniOyS9XZ544vN9bX1bktev3bQ="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-insiders-1630600136.0_1630600178331_0.959522166470703"},"_hasShrinkwrap":false},"0.7.5-insiders-1630601239.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-insiders-1630601239.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-insiders-1630601239.0","@vuedx/projectconfig":"0.7.2-insiders-1630601239.0","@vuedx/shared":"0.7.4-insiders-1630601239.0","@vuedx/template-ast-types":"0.7.3-insiders-1630601239.0","@vuedx/vue-languageservice":"0.0.1-insiders-1630601239.0","@vuedx/vue-virtual-textdocument":"0.7.5-insiders-1630601239.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.5-insiders-1630601239.0","_nodeVersion":"16.8.0","_npmVersion":"7.21.0","dist":{"integrity":"sha512-MqX4IVRPVV5yU2Iq+oaAjGlF7bUPks2IAaQEJSV4meY2gQ8lxFwmddcZqFkFDsV7Cngwl7WzBq7Oob+vrWuRfg==","shasum":"066a5dd08c988625226799840225da917dd80dec","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-insiders-1630601239.0.tgz","fileCount":5,"unpackedSize":28042,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhMQBMCRA9TVsSAnZWagAAkIsP/iW/9bHGv7dwmUP8SoMQ\nB9PKKT/MVxkL9ERVgltysKMtgjf4lhqi7bWPSK66lHzGSCHYtyo2msZ4TlkQ\nloIVv7Gw5Ixt0QFICt3QV69i7SO1+pMkN+1i/r5RDfBopWA5Rez3Dg1tM+J9\nPFWPAcdcXY6vrxbxH53+e/4WbGrAjHPBFAMrFVwoOxr8CX4coWGCuD+Ukx84\n46ZmT1NcDwpE5OLWvPfDwT3XQm/vxvZzNb694wsYLg0hcTdgbk/djpH9d4Cx\ngTlE2Yw1x8oe+e9nj2lC4Bi7FBHXMQtW/Wi7PSZzcnzE87fkcfJTIyzdjSv/\nWfwMuBuO2wnytsgDQUaSYUArKrZ9XwuFPO+gKC5VbsIabSZu1gjwlIo1OMmA\nFE9KiOWy+2uzlHO0nQvch256jBq9NgkrPBDghinCvm4ENkqDaQBOwezEb32b\ndw+xFLDsNxZ8hya96SamFmesjZMeu9uFD1h8WX1TW/8UpjxPcJrUn73FvUqi\nAav/wHCayWNolCHPrnwtjf6dDTYXQdPdOKCdU0X88yry3hWjXL40PUv2mIGj\n4pdlA++iom/Pbi28XIrsHzNjZ5mAktbXIk6RnqyyHY3cSDg2iu4uvKIDKgzK\nOdB0UNdT8Xwgh7twuIRhYrbEm3aeuxf7c/aVdpeCAmciMUu2tl05BCj5osW5\n6vLP\r\n=RdLn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA6xNNU/q8JXlvBksKdFoZUgWgY6+3YhuwPu36DUVhN3AiAwFTV7QiWMJ7KDSYQlbbUUxCApvTRnEyPZ/fmskyenPQ=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-insiders-1630601239.0_1630601292605_0.39083883480918824"},"_hasShrinkwrap":false},"0.7.5-insiders-1630604709.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-insiders-1630604709.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-insiders-1630604709.0","@vuedx/projectconfig":"0.7.2-insiders-1630604709.0","@vuedx/shared":"0.7.4-insiders-1630604709.0","@vuedx/template-ast-types":"0.7.3-insiders-1630604709.0","@vuedx/vue-languageservice":"0.0.1-insiders-1630604709.0","@vuedx/vue-virtual-textdocument":"0.7.5-insiders-1630604709.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.5-insiders-1630604709.0","_nodeVersion":"16.8.0","_npmVersion":"7.21.0","dist":{"integrity":"sha512-9Vot6qpFZkUgdPSG1q2Dy5WoYMGpgvl6qmKCYtyE7ot5FJnn57SM3so26rZqeSD8BQ0MgL+piCruqkQrQGCLlA==","shasum":"683672bbc9c058210665331fa185e1b2e48816d7","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-insiders-1630604709.0.tgz","fileCount":5,"unpackedSize":28042,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhMQ3OCRA9TVsSAnZWagAAQKYQAIXcN+5zQgUuC5lsDDrt\nFYvktzHaPXQbQWhfdlOVuYUrUFly1nlePQOUWQPQPFe28KXwLvGm2UQoHEWM\ngvWyuxoOHNTHEhKD94uuInua32v58n4k4tIitH0Qnhbzg74HU6C4+TqoVG0Q\nWfsmWR5mfkeXLZGwJW9vYyd3oW8b3W3jfYJUuI1+SUgIqit0FaY7JJrVUxrh\n/wlseZ0wZSScH7y0yjaasVoKQaFtGP6iyI6cjCBjsutVWNXXtN0Xk3YUbRc0\n4wbOjwisbcZsGpTxrzOTqAUEOidYGjDYomjAL16kztoYQM6m5vXkUnx1D7Cj\nW3SQe+T5PPBI1BoSpT39wygHWCJzHvjJMLG15LDdxrTAvCvKeJ0iSlG9NWym\nGQKHyGa+ZxulXFweQnwa+qYN82eUDgW7kZFYdg1thxXQBPKYefqZt8hx0y+Y\nrB3dZNzKLN6D0IynhlnaDDVo41Hv6vAdV4Ud6vOw2TkZwfIPHG7mBxpOpN3F\nFjbGwh8NAKh4qF/j8ei+itfXSZZyIUGCAZmZeODkrIn3HDP4YaBr29iOktZ5\nO+GhrMUea/hIuOwLE9XKO3WEb7H/y8BtHBRQfDvYKEt3LhreoLrjqbdb8Ceh\nWzIqGflTPJjAMpT1O2/vBsLsBMNw4sZAYHPbn3gACs0ozeqZmArB2zUEffDo\nrSyW\r\n=vQ3j\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC2o5itgdxm01Jah2eT3AvqDKroIywKOY39YmM3ympjWQIhAP47lEuhmX2iczEppN7LnUFiRnqvVUY6P/jJT3uOIX8K"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-insiders-1630604709.0_1630604750292_0.3856639372480921"},"_hasShrinkwrap":false},"0.7.5-next-1646032139.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1646032139.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1646032139.0","@vuedx/projectconfig":"0.7.2-next-1646032139.0","@vuedx/shared":"0.7.4-next-1646032139.0","@vuedx/template-ast-types":"0.7.3-next-1646032139.0","@vuedx/vue-languageservice":"0.0.1-next-1646032139.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1646032139.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"ac5cd7f7551447bcc11741022dacd04aa1f98881","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1646032139.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-W2rleeoXgTPDtldretpV7tjyCxHVRAwwcpF4n29vr15b4rS+5RJsJFEzWbuw48ZfkVpAyI4Ezccnl4fm7Dtgww==","shasum":"bcb4edc2854057c8fd36911f073d950dcf5db3aa","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1646032139.0.tgz","fileCount":14,"unpackedSize":19569379,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiHHUpACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrfHw//brXy/sw+2j3ClrntH+pr82yMw1R7XbT76TOAhE/39c0p8CPm\r\nndNfrJ9guKr5Tuo9+3XETmzlGqAF1TXGlm11EVU5sjstL/5vBvrBMg3GtZ4W\r\nLZgogPVq1hznUtbrjL++4cJgw6WjBnQW0dgoV4ltsS/eplPOxjbz5Ym6MXfG\r\n/zBLZRPrejdWfPlgGf/YMAkNaK6EKADlTPzUMPz9eFcN0gLn9h+L5s0Jm/m0\r\nuKdO1MVJZEvN58mFb2Htr1Wj7XH+/Lzi386obm9pghII67Xrtf1SPbJtVF0D\r\nP4EwTta2MDQdyeJIfVoSYYObaoFnrTK8ruPlnFcdpxbZHChDRbH17XIttCnj\r\nVSRlor6MoudHmAcnXQy9yi9+/gp7Cg2T8ha43z/iaSrcFtsETZRYrusl/eYt\r\ndW8E3DobI7PxXkJPmIstIdSJBePkQZdaVIs4tPvOlR5cSxw3ZrUOLrig9tgu\r\nIBamSInNrDfQRzYzHZ04idL3L5rO/pU3S9TESJzrikAkkyQKrMw4ZiBfGTw1\r\nY8x4onSq3qEQUJ2X7Dyahd+xA6NcxCBBZ+unmpZjvNy2ouOZkDEhrr+u0oPS\r\nGw/Kq2dyHFEJgt4hnB/DsJDGO4bIaMraBvzYsEheHjZcgwA0FbzTujMeLLHy\r\ng4hzkuVJryrufOyjTbLznjbWInh9uAiSO6A=\r\n=wOvX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDRcy7/i2PvMak9FKVqViAcNoV5WPhaazedaI8q12So5AiAHORTc7N7tqu6UoU1dyg4AlAH4b3gYrynHKArPP9xnDw=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1646032139.0_1646032169117_0.5235365156773666"},"_hasShrinkwrap":false},"0.7.5-next-1646814663.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1646814663.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1646814663.0","@vuedx/projectconfig":"0.7.2-next-1646814663.0","@vuedx/shared":"0.7.4-next-1646814663.0","@vuedx/template-ast-types":"0.7.3-next-1646814663.0","@vuedx/vue-languageservice":"0.0.1-next-1646814663.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1646814663.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"e3dced7823198429c304d8022b89b362bdd51a5e","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1646814663.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-GJbX5F+tLN/9xp0FikRv5nzRJAfXgf6wjqd3u9t+sDeUWn0cKP8tLyxYciiGGK54n/y3/e+PXKKCQTegL5Z2Hg==","shasum":"c8b2cd0a42a6ee73ca731e260d4b4b1a4dc9f184","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1646814663.0.tgz","fileCount":14,"unpackedSize":19837101,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiKGXhACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqUZhAAgaanc6XVc/Pz9j7ivcPGLzODMw57uXujkbcIFKx1OishrcX6\r\nd+LYinvT8jOrBvLLdp9fdQ4P6KtMkBgZiaRLfpnn11S2LJsW0vO1OCALGiGb\r\ngdENfDgbQrO95roEVcnGq+ecJs//MQtZbpz9h2v9Mse4az3QqoCQceGZC9Lg\r\ncTB1C9AkbzXkFwmWRbYXzPFf17oFhMinVg9vSg4WvXjaNXcwd+0xtmfOAp9a\r\nB+CPuI7AvZBUD9r0uSsczGHyyLsICtEb5Krq87qilbijjMqCmc3DwFvQ7Evy\r\n7oE2IH7UdKjLwM/g70L62M9pInpHdINwAQB4ygpZpeb9Sbvqyvvq8xWMjXip\r\n3mbRADB4MGvMq61Vx+O4vy6BfnLpOteWM0AV/dfQiL838bk5p+Lqcxr2xgtR\r\ndBcqUNT+2GSKpfBLSNPdw/19sF5Gx55fq1l/BwOvxloh9a8bVHDxQh+9XMLh\r\nQsVni+/34uYf1lirUppD1nPON5LKnYTzwBHxdiRc9nBVrkLXKWJs3MN+SP6i\r\nolIWmN0xTz1LmnPLX8VqrMahn3JIJ6bRT5EWjXqhz0rktM33TQtunr7jwA3U\r\nmyHLlIJPgk6PFnHw6hFo9zXHPMBj7SkNICSqI73x771GxoI/gayaJBs94G+q\r\nWaPazGgLdfFRJ2VvtTGTF0BFOiGHtXec5bI=\r\n=whMU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAaBsyoLusEL17y4587Il8O1cPVNrtziUQbqfVRpzcq1AiB825LcOd3xbuaehmjkumGDanFYFmnWLZCdccC73KeDOw=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1646814663.0_1646814689518_0.5950941024759036"},"_hasShrinkwrap":false},"0.7.5-next-1647274818.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1647274818.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1647274818.0","@vuedx/projectconfig":"0.7.2-next-1647274818.0","@vuedx/shared":"0.7.4-next-1647274818.0","@vuedx/template-ast-types":"0.7.3-next-1647274818.0","@vuedx/vue-languageservice":"0.0.1-next-1647274818.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1647274818.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"28d00a45919a4fcaf4d0888288e6b0af8e690b1a","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1647274818.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-IAxuyVWhxUVvByIsuoM26H3rT2mQ/UEbuDWenBmOuRjguCcd9/kMPQtzS0iqe2Ft4DvsudiZBLi90ZCWAHbbpQ==","shasum":"0de527f6be67be7841c56cceba62020e98575481","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1647274818.0.tgz","fileCount":14,"unpackedSize":19908526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiL2tjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmprSA/+LrCd8kS9sXRs9SYXBaxUZ8bEWl8yumwkud6F4iCjoPQWmhS+\r\nXb44z+FlGivePIh+zyh+B67BQ6Wzce/DGexb4lsvfWTxu2y2e5TCxWpAhZZY\r\nBTXU3ptB6tQ52t5tvPI23yEDtpGPRFlg/8yXGLebOXiiurc/cvk/ZHtoIVtC\r\nZ2m9yKC5uZG66ElKAntDWA+vvIVp8mzPL4Adxg0bL+S+podPC2xSq8+qNLDe\r\n4JPc+A50E5gtPseDHYFUHofK0VggTrHM5COLMj8Onj+7kAyJd1yiD6vi68C2\r\nVMYhTx3FRxeNr0ZUZjfi03UjsB1yqjWSouKmEtMDuRcSymBNMctU5Jh5AG60\r\nmUpV3qR/XTZ4Gnh9xAfhMKPAzfh16V/zL6DsVmwp7Yk5NuIwSkwEwwinTepj\r\naRKbNtah2efaxm1oWH7B3fZS3GEJ3enX6ARkS+hAgzVqxZLzMy1NpLEww9Ko\r\nupSHEAi6+s8eBl8HgeU+RIcEV4e7H6zmxaG1gNMcUnsWfPRpIuHz/be7yYsj\r\nPi2qE7IT4TrkTi33t5Q7uVlE9XUmk25oF0n1jbbcWPR/e7cmiJrZbtOm3IuB\r\nts165asLAdB7ttkrVkTvzgLD5t+MYWJ/cUHPIf+78dkMxLVQQQg78Rf/yvxa\r\nZ3EeCPp9c6PJvSm+/xB7Dd5Dm7rQYHED+jc=\r\n=li9p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICHx/jOr5z9AM5elvQWyq6kuznyEmn1hiHf9r/QSenZfAiA8bgwOVnfrw275q1WdvOTZYjvcCTHuXcrj4+1yrByG7A=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1647274818.0_1647274851338_0.9974411344839151"},"_hasShrinkwrap":false},"0.7.5-next-1647442110.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1647442110.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1647442110.0","@vuedx/projectconfig":"0.7.2-next-1647442110.0","@vuedx/shared":"0.7.4-next-1647442110.0","@vuedx/template-ast-types":"0.7.3-next-1647442110.0","@vuedx/vue-languageservice":"0.0.1-next-1647442110.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1647442110.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"47b3f73197135fe6fc58b0b738514efb6800a4b6","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1647442110.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-8K+dwKC36G6o9ljaWoLRtqFydX9v3sAnhbvTy9q+gv/3U9LvfI860rTfa92Evy/wRyhTVP8liVY6DuA6Kuju6A==","shasum":"330df0909ceca4a5fd2ec3dd15cda41fab9e44c2","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1647442110.0.tgz","fileCount":14,"unpackedSize":29738676,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiMfjcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr/Mg/+O/11CsMRg5BPj0XOyZmlunsKOR0bQOlGMNVaMOF0YV+rH+fY\r\nUSm20TkPZddbt2l3mpNrO81eQpIPm8nR7TRQ5RpPa5fR5UBL348njrq9VnYk\r\nDPmewiom/rPa7tAyjr2d/NtZJg12RTUXKZCJWo7imRwK6VksYiuDYGNsWB5a\r\nUCc17t1swmmjd/ZOa453c1T+ci86YwCbtzjP+9zwXoKmgK0sQRysJyOPj5yI\r\nAz0Xpejptq/eY0onz1dvc1LD57I8Rfrq6WhD1GbeokuNy1rMW9FN1CT0+OLL\r\nHA0ArZU5fLulWB21+0vlPnClFi+i5ZLLKCSq9wdS3F0iy4W5iu+xrOBfExTT\r\n38hV65EgnVmXArd5UqgMrbHVSIZhOzkmcQJHHFmzvQF/XM1msmY3IqkzOC84\r\nI33IvHifmff/dAJGCV/C1ZpCRVsFoQK5Yuf/QlfxmIOw5g/QORv0HY/+TVUy\r\nFHX6TPA8w79vrovCAgUwYbMwLtHTph24xUDifLov/nME+6fpfYj9NVk6Q+1C\r\nbHq/7sZagu0sgjsS+6pMZ876gvJEJoKNulEeSGhj2KoPLmnQupVGDkGf0ime\r\nhuVP7cZE1kPOCaNw0cJ223nSXfhFOCZSUpGV4SllyA79CQy8lBXgFjeziDQN\r\ndN55aw/jrre4NzB5M/1DtZTNfbMjV2XP1Ec=\r\n=yY96\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFOP2XqLlJ1afeaXYYLNQqptINu126bSxtyHeboW7x9BAiEA9PojsJ3gILfDWieIcgdaX0dsQ2saQfOD/LXz9IheTv4="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1647442110.0_1647442140203_0.37061285228851815"},"_hasShrinkwrap":false},"0.7.5-next-1647674505.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1647674505.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1647674505.0","@vuedx/projectconfig":"0.7.2-next-1647674505.0","@vuedx/shared":"0.7.4-next-1647674505.0","@vuedx/template-ast-types":"0.7.3-next-1647674505.0","@vuedx/vue-languageservice":"0.0.1-next-1647674505.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1647674505.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"8bb42206debd6454c5c2bea9b08942a92cdae8f9","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1647674505.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-s0KC9fpXA6c/3sBmlHQWPI1BwFjiUtdk9iNzLHg2zO0KamBCp0s3dyEN6N510sCyBnivraqAahsSeM3W4BG5jQ==","shasum":"d75e463c77f75e54528ba5fb7e534a439f4c9526","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1647674505.0.tgz","fileCount":14,"unpackedSize":29780274,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiNYSnACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmotBA/9GE3KzCuHec/P7aYMkdlMmxR1OQl87JHo2nHITVa52FQTQ7d9\r\nChybLB9WoutLe3z5aHyZ3bpmfSQxqINUoDIYxe1e1oc9Vl7gJJvbx0sKCRjG\r\ntn1wrh7Yb3dZ9QL6S57hCMAbgqtGo0wKdMawOZ2P77QLFMJGAjg9+Gyyb5Zi\r\n3NjHMdUQ9bHTN0JcRzGVaHNYQzjDuJw/bS9RKzyTxHGO66U2olZHdGcKCvpn\r\nG0rDuXkgCSn203nXx/yWJ6DRDFSU0Xu7iBYDK3pmyKqriQes/AmEzHXRfJZb\r\nHe2Z9geCaeWJ27oOkzrQCMmLSw7gzqsVo5oNdaj5Vh1UaqVM7kmCkfgOht8k\r\nDT/XwT3jxA6g2ScEItrSiRW0/QX76DE+GVufGceXIvJNyeK+KqtKeVCTAB8o\r\n2VhFpVxqVD/tYeCI5pLsiKepTbOy8yYtrN+Z6qab37hLuAsqcsrdT2e598Yi\r\nHjkTcDBdoi+/YPk+pQb3WcuK/PKwhAP5LWEjgiiEBuk00LSPIO75j4aIoGbR\r\nkBtAKvYagu7KZ23SU3bWczZHqaSJPOzo5gzVH37IxkdDFx4gMf1+VbNmYEwX\r\n3p4WVlPkU/gIoy9AT376IbFfNrov/adgqUxEiWavCrR3laqCN3/NtTBOeYos\r\n/SBlWtuT9xU8J1R1usVX3vo9pE74aE7niHQ=\r\n=Y9Q/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGI07qwPav5AuCB7s7Bs/WXcd0uxSNPgjqnvzUR5/NJRAiBdSVYG31mMyfiLAx/XDJx8LmfVrkyTtcxrnQeKPMidpA=="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1647674505.0_1647674535006_0.15655593966163006"},"_hasShrinkwrap":false},"0.7.5-next-1647768616.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1647768616.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1647768616.0","@vuedx/projectconfig":"0.7.2-next-1647768616.0","@vuedx/shared":"0.7.4-next-1647768616.0","@vuedx/template-ast-types":"0.7.3-next-1647768616.0","@vuedx/vue-languageservice":"0.0.1-next-1647768616.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1647768616.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"125a76fd722d6845d2c220e836da3149ed1c0177","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1647768616.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-3YowrbxMBL3HOy4Yu3W3u5mzu/EsQYIJOWbrNGlba+LD4sYDvpCAcvyhixf/y1SXrS5q4VarjuVdBVqE6hVv2g==","shasum":"aa1eb6e80b6264b13d4307e6997e1e1687799283","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1647768616.0.tgz","fileCount":14,"unpackedSize":29995830,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiNvRHACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqEFA//YHt/zWVBI0u+LCA9xCavNOsMpapY8NNEjFKMzP5rJm0n27pP\r\n3sIqSFRPZ1k+0y1pxaMcjEEUJ5pNQrGZ5TYnAYv6jr1nhqOOGj2QndhyzW9z\r\nbl4JWYKzx45cHFPVF1OtubPkE3014QRvMec35nTxABg2r8nYwwimLz/KMoHX\r\nlwRtB+UaLrbqdBCCb/0pKFe1rsfZ+v2JyGucw1h+hE9+HQyJboNJGjqhznap\r\nbXaGY1HrQqZ3Ymyva/ovZnx4Ae9AkeV/vGGrA/gDBMLeb6kd5NaTB63mMd05\r\nAPhq+3Wey7x9jtLq20RJ8B5Mpjj8rFeplt2U1PYm3e3T+7h4SxAU8LOZY/I3\r\nkWjY2jLIfK0iiV3SrVtvrfFGCNbYWnFsgLF6ndzYAqHQuNjIWP77EWmNxtVr\r\nTu4al4d1aYF42wi+kOWIoZsQmgTCG2+nurfLYof3mDy8gzLWMnY5FPhUz1sY\r\nStQvghVjfvseIJ1AHsh1pufK+W42thvz+/pHFdQnsnaG7WnJgXGZbmpjie8n\r\n7rgR/zskOgdbl4+cHDwe+lWAgU33TswAKemDO6vH4t62nsHnczuiK6hmlBYt\r\ni/IV+suyN2ooxr0ucnFCOFvAax0aO4kHKq//Vsgcq5N4Yt5jw+k3e166gVf6\r\nROWY51gfzgTKLiJnhvJ4/ufiF1LtpsOVVtM=\r\n=hlHQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDDFXUap4b8ekZLl4KmpWbiAYQujNNFmP2PBA/Wl/O1DAiEAn+z1/9newP9j6E97R770Nkp3EzMLzTduXMv/9nhG2CE="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1647768616.0_1647768647147_0.4838885509261399"},"_hasShrinkwrap":false},"0.7.5-next-1647933433.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1647933433.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1647933433.0","@vuedx/projectconfig":"0.7.2-next-1647933433.0","@vuedx/shared":"0.7.4-next-1647933433.0","@vuedx/template-ast-types":"0.7.3-next-1647933433.0","@vuedx/vue-languageservice":"0.0.1-next-1647933433.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1647933433.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"35ec24dcf4fc7e46e517f2d1eef106314ffe67bb","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1647933433.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-Uc237vzXvBNXwF813sp4WICgFJPj5fQs7EbWvu5PmblzA57QbwaP4Kdc5fuhfKFb3hNvJqdY3TvctH3kuOrqzA==","shasum":"4d2cee0204bdfe2026ebe5603befe365dc49eda8","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1647933433.0.tgz","fileCount":14,"unpackedSize":30004605,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiOXgUACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqQEw//Wy7KMdozLPkkhwvNnTtwD46OF0bahEHXMlRP53R9AxHb9Hfk\r\nyW+LPhboLa2lfWCbXI+D0spIXErtSbAINK25FlVTrZoBb48MtPHd5jMg2Yj2\r\nm7Uzun5mbH8DziLb9dOiM2p+DCsJB0cIHD+1OpNT74bxJSTN3/pIuzhzehhw\r\n1+KmB7gDazq7v+MQdaHwvCkKqWAjrbt8kXzmtpbFOvgFntCXWXLdUmBYpn6y\r\nsNFU+mrB/SFtQEBd3QcEx4ERrATaV+wORpWjz/3JRKyqdPSUNvlPzaIfaQ4+\r\nZ+ZOyjBdFkae5FDbT3T14tFg88jtgedvg/qAm+y375TJlElZF1XKq38vj6s9\r\ngNvTOJ0hlpsyo68pZwj5ztN9wzsH2/qlpOA/jFFscD8lvXdhrc313MLWdz3R\r\np6yqHmtFDOpJEXd2/ZA3QXBa5wOiZp12kyhRsXEM4kEcru3XQEj6ScBponon\r\nVtobKxXttEksiqX7INwm5TB+6EKzl1RrSlCIagpCgt66sVVG4SOorqD/azXK\r\ng0eWVyOKBNqEMBRIsCbMk6KfP8voMqnD0P8Y9j3mQ3yh0Ewlh5aivn91cwG1\r\niOVoWQbIgZx9GqU9D1Mwu2lDLpe9E+l7Ecq1NuGwQmxeZEld6W9CuYK2ZUMW\r\nm8TsnhT5rTDzsb9FXBTb8YeA/vper9nGR0Y=\r\n=3ZRs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCC0fQO0kYigTZVhLS1Qa339mPcGTiC8r7MkPZ1wElyVQIhANkqz3wDLlDRLBBc+5Wu169YI/DyuLemYuFUE/YpiTdB"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1647933433.0_1647933460662_0.5003596682169922"},"_hasShrinkwrap":false},"0.7.5-next-1648400394.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1648400394.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1648400394.0","@vuedx/projectconfig":"0.7.2-next-1648400394.0","@vuedx/shared":"0.7.4-next-1648400394.0","@vuedx/template-ast-types":"0.7.3-next-1648400394.0","@vuedx/vue-languageservice":"0.0.1-next-1648400394.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1648400394.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"89c2a70e2cf0352dda64152459bcb0f37130281f","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1648400394.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-IbtG55llqr400ATzl0BYc/fGJXtUWALRqcSF2dLCcaRdU8WCz+JeR1Tp63r3ACSng4RJJIhAgAYxEfEeHgdGhA==","shasum":"335fb46003a2f953dfba62ae23b144af91c07c8d","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1648400394.0.tgz","fileCount":14,"unpackedSize":30061963,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiQJgoACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpSQQ/9GZ9Q7YpS4eYE1MYJ6xEaNdClNbbpN6RbU/BZs5b1rEpFBCfg\r\nwlH7SEFqQanzala71mWEvbHak/xAJP172Wks04JrqOPBMyczYGsJXoGoEO1V\r\nqtDN0FPgP5d+Y3cenCZplVUWR+T9sczdaWGH45V4AS/hBF3/vVkVI70SDCQk\r\nalg3hqKhl8vTTg4112ni7pAXvt2NlPbqLS9e8si0D3z3YBrjEYSlMYxUSSWF\r\nZBV6xg2AYCJBK8Uh/inMUosF8D8p2eY+ys9Ve504dDVbFK44hVrAGauoOhNd\r\npwJhRbX0LQ4zWF1Q0dS0ey+tIb3lXv9E9OhFW+UR+lKzAB3d26wYjpHddEV3\r\nl2l1BExqzC6LSB+e1yPj8Y0jKIML/lGYLTHRWGt+zxfKvebjAj4UOAfjQ7dk\r\nP2aRlv+fOcmHQ+S/fznC/RSVznUqiDH3CJRxXXz/Sk7VWdkNdmkcQRpC6tFk\r\nhX7UzvM1kViasgsWkSOafHNgKZLFIbW/i80tHB3Q1rjA/0YpSLZMwumVXWJL\r\nabAJs9DVcO/xeAycYLIdbmhaP5+SnpstAnmTbTKiW+xzfauDFBPEgPyBY1fu\r\nhByFT9f5dMdeIDU3mJwVka8gq9o5RpyrjZmbV9GBdtX2fbIg57u8WiuxAnUK\r\nDFBE3Xt74ZE9l1lB6XEhkQ4LaBML+xYvORs=\r\n=JX/L\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD/ZX35/3PAw9nBGjgeRDBNoyY5k51PpLZ997ZoygeXyAIhAIGQlpzpLfTASc4l7L4bG+8SdwH5+BitDDjt8Xi4RXb3"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1648400394.0_1648400424407_0.5500845164734247"},"_hasShrinkwrap":false},"0.7.5-next-1648409815.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1648409815.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1648409815.0","@vuedx/projectconfig":"0.7.2-next-1648409815.0","@vuedx/shared":"0.7.4-next-1648409815.0","@vuedx/template-ast-types":"0.7.3-next-1648409815.0","@vuedx/vue-languageservice":"0.0.1-next-1648409815.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1648409815.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"a7e5c298089ba553cb4804e4b9c5606a57dd4708","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1648409815.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-NHJBXz6Wy1/OHoHDd9PLIUvzeMu7nzZc8DpOdNTgw9yDarZRnHhjYtaT1UDLExPDuv5uEUtYEMSxuYU5DLQsRw==","shasum":"5d5f084807d5dcd0c09f2823e8b7ef820f3b8710","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1648409815.0.tgz","fileCount":14,"unpackedSize":30061963,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiQLzzACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrLow//XhTmeNmVS6wVsUlALU2pSZelMvfaG7gbNiSV1m4+kmsk/r8H\r\nzPXiL+WePVxcqB5Noj+nN++VBfI/m/TlRwJUhby7OU3Iei0vmYK8c4kkSggG\r\n/43RwZLOe3NFRuI1aLhAMQKIwKQSK8LV9tbfAPmGUg5xoY2TeJe78rpe8beI\r\nj6Lj8o7TyS15UYHHGyao0lqi8WUF8z3xfmT3k0AFc68IcE7uXlsICciXxQ2c\r\ntr58jFKHQr1SEqUlyktEvxOMMWltCNy44gIlpHNF/UBgar2fZWEvBYPUIR53\r\nA+9Lc2NW0oiV7rFBgbZ/sOP0Sh5DvNtuCKivzx1yse7v9ueCZgOps7I2JgGU\r\nosD9ka+Jty2eLPVs1ZOV2YRQtz8NtfmK6PHvSYHSstzZO+SL76i/MwNfjFcE\r\n1pQ/n5EsfGGzmaloIkLj2suH2ybns91jO3bkj12DKvvssLX6udEVVcwtks7D\r\n+hkQfbUVywuRWqVIxOvjfa4GhwWFDw9ESJUlWZ4YRpRDKTQD/+Go7z8RbS57\r\nSsZW1+3f87P+j65yqC9TY6vFPX3ajviIhMDwSijlXOEwS3rPWwFppOLdUJoi\r\nePH3GNyW4xT/xqOS95PdplbGVf5PnMvPu8zlRVUP5Mu3Dee3Z4JQmFDWUp4D\r\nG9XvvhlUc8NU8plQtF9s/d/egFxNOrSo4xo=\r\n=nJIc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC10frOcoi+ihcIXJ9z2j/4WFXnWK0q8p7tef+Rr+xcMAIhAMWZ5c6L14Dz+HGXCkJo1NKfrl6AMN+9H1Y91sGyGUmt"}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1648409815.0_1648409842768_0.0059314763462490205"},"_hasShrinkwrap":false},"0.7.5-next-1648411566.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1648411566.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1648411566.0","@vuedx/projectconfig":"0.7.2-next-1648411566.0","@vuedx/shared":"0.7.4-next-1648411566.0","@vuedx/template-ast-types":"0.7.3-next-1648411566.0","@vuedx/vue-languageservice":"0.0.1-next-1648411566.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1648411566.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"f2aefd5bd4cfcf3f762c47f2132a81d75901f77c","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1648411566.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-SPiv3flni9fgHtWj5I7jqL4vSWOuPahHzMh/96gd02BWf08FxLjDEa/U9F3th+GJpvZTj2Wvxn/ZaU2lsOUdiA==","shasum":"aa2abeeb1842ae7ce713da33bbabaf4ae76c0734","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1648411566.0.tgz","fileCount":14,"unpackedSize":30061963,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiQMPKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrDcA//fKxrG6Ij8p9wdX7+azTuq6UNgHlUZ7nUcoY11NmYoiALqxKi\r\nPrERQFRVBPAEoDUtV7veB590bNIZrvQeqeAVRR8dG+63L+GYpOEkrpKNxUYj\r\niGU9NcBPlHKcbQ6LCogs7fITAATOxtQ0FDsBpgz9n6Odi+LCsfmo8JDnSN6D\r\nM85Vh59VlCTbfWPVX6ev3GJtVPtwISVRH9BXxnk+Q+N2uNqabCZEmquYrJZx\r\n766Etu5qeyqjGX5tOnWXc6GqHMArD0xNc5hpPYKYn90V01ltp4PF5ZjkERWP\r\ntjL0x2WeNdtp+Ri6VjgKOdUBFGyIQpM5KBO3kN8e1NogE/T5gWW5AVubtKWy\r\nHZjQQZcr8qj2N1jfqT1Qy1Z/D/Ocvdjn7xgRXPNoizKosQfKk8eYinHsj6qm\r\n1m47am6znU7O6dA2x0UH+UnKERvBZa9ba6lHKC037DavWvti87FHvFSY1p/f\r\n+DIgb+gHBI2lPILiAsJplBZw9w5ONmx28xw0TpFkbfWZSBG8VbkIuKh2b8qB\r\n3kaqnku+ibpFRKNQEJyfvn/Jkv69H5RdrwCsgaYzrQpPgXay7hgjBlLi4Ur3\r\nmKOIGXQP2jz/YA93Q3X52egu/cVFEMjWfjpK/H5SOsXolQvUMahoGh5LLVSp\r\nDZ8n8g1S6nGdmCmmenQsTRcJDGvjiBTRcKM=\r\n=n+yA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBGr7bZbngi4vchpb9iK7xQ5LuG6mKhA4mRCmIRD5yoaAiEAvrb1qdq9sNTlKXUsnE2YBpd27Ucl8Slsg06wpaRWb6Q="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1648411566.0_1648411594180_0.10051401981380326"},"_hasShrinkwrap":false},"0.7.5-next-1648440991.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1648440991.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1648440991.0","@vuedx/projectconfig":"0.7.2-next-1648440991.0","@vuedx/shared":"0.7.4-next-1648440991.0","@vuedx/template-ast-types":"0.7.3-next-1648440991.0","@vuedx/vue-languageservice":"0.0.1-next-1648440991.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1648440991.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"382f9718890a2480b517f459be68da34d46aec77","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1648440991.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-pfWB3y7Wn5abS2wLRF2iwkseBNvzh/h+aPQYLBrWUsh6vUJtNuO4CszMHo678essSvDcFpwrbiEgO/86tcn1vw==","shasum":"0750ec1981e9e60670b365995abb6ddc741154ad","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1648440991.0.tgz","fileCount":14,"unpackedSize":30086547,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiQTbIACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpL+w/9ETW0xJSMs0jAIlixw5v06GJBoys7tWo5/UnKKtzMaGQlCv5v\r\n6szO2DEcNImZHRoY8A9zQLkgSPml3t8gYnlbYd7xjTgq4s66fyYHRDS/QS7N\r\nouwRd9vUoTN02BIWToAS2X/7uW76NZ8v3rPeaeINZyvFrrMrYtLrcUn9iRSZ\r\nP+/XWuR21TghXd+g/VWc2D5p5hV4fZpvrABmKZh2hPHpzKxW5/uQvsCY3ijj\r\nIGLOYa5nZ0R28DaNRG/1XFW+fOBmWiYYQhZ4G2yV05cZKxu7Ti0xyZbvWOTE\r\npHRFyov3QlMFgvfTPdkySXkbaU1nj5/z37mE8YwcMJE30Jx9IDYTJLXLOu5q\r\nfeaoqkIz+kcoc/wjtBqPohuRdDl1nLI3PqpvuWZw1zwNHwj72Fz+YVZ2wSfh\r\n71/Af+Cr201Wb8/4+8i50/sC4OZ0UXOdms9Y0czS/mQcSq0JMcYI+vHrttaa\r\nqlhMLcG+qq/OzTm0gyvMkpK4x07gXq8PXQD/kyBXMXU4FC0SRUSanlnMVJvF\r\nXBHKgckFk4vR6O4HjNGtL1G//CVskfDv8KMCWJm+mDrz1fQpjuoI963sO8O/\r\n+X5BJhbLUTfyW7l1Brbf2oxsdpQH3yoMHjIWMRoN5Z2LeCu/yNIDVYB2f4zT\r\nlp+h5Thyt/PMs0dqeBd7qNhTjCEIK+prwo0=\r\n=K9ek\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQClLWUeNauHLSqqbkG+sm7N1XQswS1yuNFTzGoP5lsEPQIgMwHfLym/OkBxRK9ZoU2q6v3pKS8atY4wq90GEEuVlpA="}]},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1648440991.0_1648441031893_0.4374781201326534"},"_hasShrinkwrap":false},"0.7.5-next-1648822539.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1648822539.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1648822539.0","@vuedx/projectconfig":"0.7.2-next-1648822539.0","@vuedx/shared":"0.7.4-next-1648822539.0","@vuedx/template-ast-types":"0.7.3-next-1648822539.0","@vuedx/vue-languageservice":"0.0.1-next-1648822539.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1648822539.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"7c910a66ee0f71f9899409cb746434e75b4061c1","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1648822539.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-qLU7IzDKJ6G5sAzzZMYwtSf414VtIqVs44IfM60x5ExbPtacSN+Jnrmo4ClC/JBIhjJUCeThDHrgTK16BYfNbw==","shasum":"fbb13e0712185b20b8d4067e24b186605992facf","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1648822539.0.tgz","fileCount":14,"unpackedSize":30056519,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGDvhnntLBLj4khnm5ar9YPrwWb4VHALsG3T4FEnBd6tAiEAzcw4dM36EFzbHepkmobTlImMS05ykA/fRlAYPWVH9R4="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiRwkqACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo+iA/+JIjU+xXzxluTo2EAKx1tT9hnQFRX58Z59axijuDLI37GVxWu\r\nlmoy4RlUnfmMR97LAbzG3zGVUCAQsRih8+8OcvMAIgebDei08IEBwbhPe2tE\r\nIDVeVib/o7ykqFElfLjgJUrW+fj0cwiHttUfiEoMkbt7hCMDX28M+89ebDsQ\r\naOBfo6pPzcVUicm4nLen5ps9wTPcfeeXhetLgrFphKTKeo/vS2MHqaHyqZLS\r\n56oZOyevF7dbb5AISc/qx17hLHBmyFpfHtje7mQ8/lvycT0ILRly13SenvCq\r\nhJhDUeQ4q1mT6cJwXninv9CD1Sa3ZwDeYbZdPFK+ntowgzCJHTFqtWf3iS+Y\r\n5/CkBrGYoicGLYdoOPbWNeyTg7sZIZKtqE1I0ncIl9EzgAi7y81roIQE7oS2\r\nVybYTnCJT1VGZDkTiaAWcnUkdK5plEJwCIVpJ93twFWElMhPgi46/AzU1tsd\r\nXpplYhMLzsHXXHeq2pjpWUbxEhesRGLp7s71wVneBUhi2ET8oOaGdp6A6uLZ\r\nF37sARbVNLsG/5mdjc++VmKjXO88//CAlImtzLpw/T45kUOrT/wNCwf+Hn9+\r\neYtba0PKxlRQBZD0UZeuE7DeiJ+TMirPU+nUg5OsCwfcB6iVND69vIbFWgcY\r\nSueMz8chmrYeXHMmSl6AibhhX6iPXM2AqR0=\r\n=tFnt\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1648822539.0_1648822570416_0.5658347692734904"},"_hasShrinkwrap":false},"0.7.5-next-1648824950.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1648824950.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1648824950.0","@vuedx/projectconfig":"0.7.2-next-1648824950.0","@vuedx/shared":"0.7.4-next-1648824950.0","@vuedx/template-ast-types":"0.7.3-next-1648824950.0","@vuedx/vue-languageservice":"0.0.1-next-1648824950.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1648824950.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"8c90abe2d190f9248f41af6385f0238b2ad73fe7","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1648824950.0","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-96iyetmvYc/h2arzG+5sHsGEeZKQ98/rcm9fgslyvfJRJzoatBKH1SLpQA8CiBS/8NbaEC4QnLfv3ocfTcKqsQ==","shasum":"9c4a474cb113b1cb0cb63b3a33eb648c048db6ab","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1648824950.0.tgz","fileCount":14,"unpackedSize":30058979,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGPEgjKI7rR/ZIbJAAvOtTp6B2FQ7HQxOTz7tw9qXtRBAiBRIEuckzBf1UMpBaD/3YWqjP+PGhiSnAeW95YakP8eVg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiRxKVACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr9aA/9HnFbocXXs2xuO9OkvjDfbUEuF0tJSnaglCD8OGZqusuIvWsy\r\nJYpHP2u7RxdKLKFN3CMN8SmIRACWOHFoFzJrpYjBQjPzYxOuv42Sy1OscgYG\r\n6hMG/Cm1RXsOQ/D//A2sv2GBRKOd6iDB/XYKhN4OcN7rOFraSYuX0pbpyJuM\r\njcbl0OxH4QtWroREX0P8nXkFsYJEOaQGCUCPvQuVufdoi/ff7rqIcGi7jDJE\r\nX4uOCLX2WsjnjacfuzYOHoiUDLNLybt7T37BUoXFYDhTF1wQQ9zTje5RII7s\r\nROuPn6+05xd3Q4rPkG6ZozREYma4XH9/f/mXIztvztSELV5Bni3IKRapItkF\r\nnZu3PaRPuIhfj13nNBdn5aU7Bs5uiY6za+7fPzG7Esubb2OisQCOysR3oZFC\r\nTplzDpVEAtOF6chG1SH85eWqMmf3D211qw1/t7cE4PqLd9gH3nVP7fB7QKU5\r\noUN3N9yysAdBCiPFgnpr4xkPxA1Zi1WLvNF1BsgLsvXS9VaqYLsfsQcj8iYL\r\nycx3K2s1DDet4hLiBOfgWNOAdF9MvbbTQt0AAzoNHeXCxyEB/r08Vmvt832L\r\nbxmf80RC72tKUqDvcatkc3oS7EAC/4lmgJJOj4E4k9YPv5uuzfW2ModgJo40\r\nFbfjgFx/Rjn1oiQtZWv6+IC2I5drH5HKuKk=\r\n=KWVi\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1648824950.0_1648824980889_0.5085944098999313"},"_hasShrinkwrap":false},"0.7.5-next-1649087720.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649087720.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649087720.0","@vuedx/projectconfig":"0.7.2-next-1649087720.0","@vuedx/shared":"0.7.4-next-1649087720.0","@vuedx/template-ast-types":"0.7.3-next-1649087720.0","@vuedx/vue-languageservice":"0.0.1-next-1649087720.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649087720.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","tsd":"^0.17.0","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"scripts":{"test":"tsd"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"90bf7b89074817f7edc22b2e6734627d3a4c9d13","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649087720.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-Cf3WiUmjiaa3ucBlV4LODQMIC6LRTamDOak7dgK2u8Bj8d71zPrhzzlF7JxZTJjPlxe+CXFiGKLLUNlKy1pU1g==","shasum":"7be647f05266ddfa0168c0e16cef159b4cd739af","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649087720.0.tgz","fileCount":14,"unpackedSize":30058979,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGxYa5SeYR4zw481gKB4sBDELyE64GnqtsJEkPEvnQ3XAiEA5TpMbFLfDQBjxZjz1Ns23Lo2Cj3sHAISqP/nwsxmOkk="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiSxUIACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoEgw//U7uCo9Fe0P/KjHrfNf3egDZd8AWa2mEFZihVMEL1+iSmD49Q\r\ntvqtDR6Y5lcJdogGmGr1/3/18tHaGIcE/aZbcqTmTU58MUoTs4N6vYisbGHC\r\n17uUyWD2616R00BJ/Ovn+bmSYXdHc/E8gcfkdWU1WxjYvKOKhj/Xcfs2gY0E\r\nugw4Qtwpcxw2HO6vddBHoOAiKH5InxBN+TTh3Me4dxWfx5yGPKF8us1P+Kx0\r\nYDrZJi9JwZBqCeDf+akc2p/enB5h1Tzo95CPUh8cRdSzkRpT2xMWR4BcWkkl\r\nmuWAarYRaBWAq89CaY2uHxbDwSgqDLK8eYGfXfIPMmoniotUqHGI3+or8XPV\r\nlg/Unw7qUOzWyi5SloCI8W+nJfNuRqBaqAaJpzKR9+hodqTr2ggtKAPFSBxm\r\n6FHzOpFvwakCozut5K2t+PjiI2jatzD8xImjRdL0TU/xmafxtNlGNZZrAcMg\r\nmEt07H/nGRO72W+pLxGH7reCvSW+bFodVTuBz62FIILGygGCP+JyT9otD+nx\r\nDCW0Ip3eOftKqA4/WVv7bJ3rwb2h87T4xl1YFDm5N9DtLWL5qwfIBic2D4Ho\r\nUSe5Bt5PgUEnUPmVFcWM3FJpZDBSpNxSS0qTntx6S4KE+YYH0Nnez5iuBnp+\r\nFtO0l9rfEbZvlfMIAJ2T8dtlZDzPf6E40MY=\r\n=3miR\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649087720.0_1649087752220_0.6483127351599975"},"_hasShrinkwrap":false},"0.7.5-next-1649225489.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649225489.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649225489.0","@vuedx/projectconfig":"0.7.2-next-1649225489.0","@vuedx/shared":"0.7.4-next-1649225489.0","@vuedx/template-ast-types":"0.7.3-next-1649225489.0","@vuedx/vue-languageservice":"0.0.1-next-1649225489.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649225489.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"1fc6c58009b1593eade1c94397751d176dab4d19","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649225489.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-90j5IGE9ZmDGuwrwM3DhWmzibGUr8I+2b8eGqfeaVQeTrJC1taHQhyWO5RLQXWrhqM201rtuNNmULo7Y22tjEQ==","shasum":"c1347f4f3c46eeee3e5c1c03df73f13612f77c7e","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649225489.0.tgz","fileCount":14,"unpackedSize":27407747,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF0FWKivuNTU/Ams2isX6/oxgDaPV6YhAr6wYAr2OWesAiAQLvCJ+XR/V0QKDjlhC0DyNG23JaLH/SU4AB68/lwiCA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiTS8vACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpB0xAAm8Kadm9oYA4wXY7AJIs+4bwGxCcs1XNkHlbTJGvaA/UOYOst\r\nSay66bfKSJnKPqyRkH5G+JK9iZoehB0FqKPSk4uU9Zz3HC3mybDNiUsh0DDH\r\nyqRelWCGBqxz2NsZdgS6OPcaxGLIoddrwmcKICLIF6cQSKHQQt6UF0V8/uq9\r\natDqs9jPua6THNcr9kEJROzO4N3UyaYGJaMBiMH30Ph0uvUVdSWLKqFBGk95\r\nKo772jlg1B1ofgG5NPI+MhL1AcWNlQYlu7Tc6AFvGC0I2lFFzKdoov5KG8WV\r\ni+uiZ4WM8zLJCIv52eaSbFS3S7noF8HMBcP7lRfESJ6gBRHkH2ucMmLz+/dY\r\nsWCw0AgaG5AvVNj1L8h25HeTYAAf6pnifUCnFRH6/jH3flqtMSgvYcujyzWp\r\nQZb5WOMTj/O11huMQ/Ouh+0f7Va+XUAxaKx6Vtwop1wsW0iaRje+3dZSFI3t\r\nP7U6bMjFNalePgIpAbl5AUBgGq940iDePLo9GugCoOWGOcAdtoeQLtZi6Gts\r\nvpbNcJGHvcWJP0dKKBUhdCEcsr1hNT5IG4M1Bh+UPFhcXlMOTdw3eHracuwc\r\ne1ZztnNPIexdgBDXDbL3+aZr0nbiGHjuEMvV0P+NfwjqVevDpIMCbTAsGBil\r\njov+7O8PKzjTyfVQH8duDzh1xj6IEF++Ido=\r\n=0F5R\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649225489.0_1649225519442_0.5301560939455723"},"_hasShrinkwrap":false},"0.7.5-next-1649228283.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649228283.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649228283.0","@vuedx/projectconfig":"0.7.2-next-1649228283.0","@vuedx/shared":"0.7.4-next-1649228283.0","@vuedx/template-ast-types":"0.7.3-next-1649228283.0","@vuedx/vue-languageservice":"0.0.1-next-1649228283.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649228283.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"28b63998dca864cfc36df19115885521f6918162","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649228283.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-l+EgOmKhuh1Xe1/eAFlvOO7C9zB5ud1imPwu6FG55S6bl3vn3HhzB08aPagcxcUGr/ShdzTI7QpXLKRMDnapYg==","shasum":"128b07c457f45ebca11dee606986ac1b70a3f111","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649228283.0.tgz","fileCount":14,"unpackedSize":27408623,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICc1KSd8Nc9JcU808Apc2+y7Jhny67+wktBRu+BS9YUoAiEAjIY0BbonImVdsyQnrXUnXXEQr2eLeuAhwZ+KuqKXmIs="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiTTobACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqo3Q//SMs1qPkSBV/m+sVXCdeHh8vrMBK/1Cb02qEWHMGCkmlIc5Xf\r\n5XrYko0Cwejr8C0QLGP6UDyS530pRGuK/B5pujqznwfjd1fRNBjJowzIoK46\r\nWL+64AAVxlNCkqJTJjAc506f9pE1crYKO5BEcfuv8PX3Gj3+kjKU3ZgtG4n5\r\nuA4+k/Phd2cVWffTZTB2/fHrwsibO8h402XZBh81YV1oWByhZQqXVplbLBjc\r\nPjOAcVK/uU2FvdOoow6gDgLvZgjJOXHz7SUuCofvEtuzgJHht+OvVI2LbKwq\r\naxH8/UZWhRI5wMxTfYEuXcD0UTrRzGI0P4g2hx3F4agEbeNdZBTQeLeqxK/n\r\n6FQkhYANCSjHpHADOxSxN8d0ISGX+UfV0aMOy7pHCtvsV3EbRRGB+bqj8hf/\r\nJIN64v0p1LGef/doXmnHCc3X7k7xMFXIEX/IOcex1+RqIZwmmagUFolWQSHh\r\n4U0cI0dZ1fTpHfZB164FVjjI5hKZiuhAs1CJrLfOYAqh0eAllVvMgZf21Dfz\r\nnYQGjZvRr789iz/xGelAv9e+w5lQt9FXM66+yeCiqdbuHnWJ8uV7PhLLNIw4\r\n0jEqhgw6GMZSWMNFpJlopzQlZu/8VjTctrnYghASAtcrBh17/lFs7DSRs+h8\r\npk2Zc2/NnIAs8rg1DQsBW805AHcRAKtEooI=\r\n=KH5r\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649228283.0_1649228314839_0.6759253344434064"},"_hasShrinkwrap":false},"0.7.5-next-1649315434.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649315434.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649315434.0","@vuedx/projectconfig":"0.7.2-next-1649315434.0","@vuedx/shared":"0.7.4-next-1649315434.0","@vuedx/template-ast-types":"0.7.3-next-1649315434.0","@vuedx/vue-languageservice":"0.0.1-next-1649315434.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649315434.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"909d2074f730b03ba508050d27fa4d060383118b","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649315434.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-EzUi4ljHK/q4WZih09Nl6fIUvz6WwylW8Aq9zmtML5hnNb2DB9YLN+YLCPJKH+Q3G3KZ2/JMf8oUDIdlFhjSzQ==","shasum":"cd9466c8d7f12dce527edf7f1251a865a00427dc","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649315434.0.tgz","fileCount":14,"unpackedSize":27422159,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICyvPjI0EK0JvNEY3iCsHAk5VH7kD2gZMrXfaZEIzRHjAiEAxD04iywv+IzHUj+rtcBJexwuWo9R3wE41UYosmqyCUo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiTo6GACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmokQA/8CZmXyoJ1OXPqJwH0ifvDt3iuH59GnMalq3fGvwebcv4E0srz\r\nCHjlYU2qe5DJZp1nJkPkVJf4XfI3ZM+ACU6caxYjP9+Gz84zxsC1TYPd+Qd/\r\nAPRhSheWNi8qkaL7nu8Qjv5p85hE7nh/r6QJRNWyfsUCtGLFVrOYdolaK8Wk\r\nouE2RO0EhPL+eUTosAloiNYkzSp4hrQv635uf1sUMPRZH5lCreslYYgpF6xm\r\nsNGqxsxUYQZf8as3fe9mY/Xo7PQqvudpDH8RKDu7Tewd9jXzSoMVgDaMv1n/\r\nxb5dni3Pui0NoeotrAWa4bu+10MXkCPUzh+ThZNzR7YxUGaegZKW1bX8v8t8\r\n4zoy8egS5Vbd2On8wB3feN0/V1xqVkCX/kaqXkjmf1fvjE4iybCUXK1JTWHd\r\nWJfsPDlslSN/3Yyx0HUTnmymRpDeMCjEte+e4PAYwAU5TO8oQOZ9js/fiv17\r\neaC2Rbbd+A7Wy7kkhkzpcjbD1O0HBn0yVyyykJNr10Fsyb/aK9jL+QfgrnHQ\r\nNt3DFbAbBaSWeq7pc5EiUNaCDLt+srVum/rDtt/MZBHzGPA/K9iu4VzADUo8\r\niTkyreRehdmCqbYwm9y0xQieijs+q34x++QHinSGn4DkE8AbxRBU/Riccrpb\r\n4j7Gcd/IaWKC4DLUgraGnpeGqA+eiazYb6c=\r\n=CMr1\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649315434.0_1649315462424_0.6582323142461612"},"_hasShrinkwrap":false},"0.7.5-next-1649381954.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649381954.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649381954.0","@vuedx/projectconfig":"0.7.2-next-1649381954.0","@vuedx/shared":"0.7.4-next-1649381954.0","@vuedx/template-ast-types":"0.7.3-next-1649381954.0","@vuedx/vue-languageservice":"0.0.1-next-1649381954.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649381954.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"3035e141a59c7b5ef22335963cbd16e2d209c35f","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649381954.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-sFYYN8OQJ/kms59tmQ1p2cVLU4KW7hmRBiZCdrA27HO8Y8Aq6i0+OScLaDEqXvxvqxGzwvzV51rel4zuw6u/5g==","shasum":"572eb551e253fa5f52be7db5a62e6afc64ffb76f","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649381954.0.tgz","fileCount":14,"unpackedSize":27427521,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHhd65oGo8qBQkJqrsWVbjz3P/W13rSn4yI4Y/8cgUoeAiEAiUjTW5BkcFb+j5EisoSMf4w/w8ruyGOLm0cDJnAshpo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiT5JgACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqkew/+N7xz9QU4eXPAkHM77Nk5u4kqKUG3T9Yh2XuEV0tgDm8G34Ev\r\nlhq4LXRBYnFmJArq32EBsRbN0K/7HFs8F5XYl8mtyy5BQQONgjzgOVgVTqQW\r\nuuAlUSYJ5oeWglhQAQQtM5QsMkBo6k6AStzHhSDFVp5kETsYFO40jykbUBQJ\r\nkOF77R2D2vN5zghrbXAXHhWDmNGmGEvZS5nzY/VotZsDUDflii9PTgA34cJY\r\nqMeWSN3tinjz0BqnB4L6SYjrinqGGnHsMt97wURIIODLBYR7k3/s+YK2SHUR\r\nX2LHdBrvn2Npw/maqFCWC3cMhx6wKRftkH5TKcYXEHRvadopq7Ae3wrYJwuk\r\nLiaPvNi28ZY/TjZAA9yWv7x788UWbJV6X3KgQ8YeRgmGNYXIp2kz0SE56nt/\r\nmVttKthG5IV3ehi5bQQx4RFGRYbF4d9jam2Mq9F50UzrwfoAfh2f3rOeSfNt\r\nvL6DcsLsN0DkG7W6KqqQcyoiF0/hBKFoHfuGfTPFJ4cphzwN3gwkB0Nc8Ao1\r\nsdPKvaAPFq3+HG4WaNiUItBM2zbDWTv8Z78nHloi2/GMSp1gGSQrg/wkm7Lc\r\neftm8ncsnPAZQcQSKyTsXNCo5mL1UfygYzVCOBppXcyiYsThFe7CyB/azQ2q\r\nVS2nJbQA6NRcaJQCcChgMaI2D5ZZygAVMVs=\r\n=uyEh\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649381954.0_1649381983958_0.22202637983479723"},"_hasShrinkwrap":false},"0.7.5-next-1649388850.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649388850.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649388850.0","@vuedx/projectconfig":"0.7.2-next-1649388850.0","@vuedx/shared":"0.7.4-next-1649388850.0","@vuedx/template-ast-types":"0.7.3-next-1649388850.0","@vuedx/vue-languageservice":"0.0.1-next-1649388850.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649388850.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"94505e855a70115f0f82d9eba4fdb775ce8e9914","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649388850.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-3p4NdO7FrEScLbMi36IkX7AEze7Gpk3gIsZZh5SktYekUeu8zqb3V7CAlEcUemjWyrwGwr1jIxxZSzt9ttgi6g==","shasum":"3ca065df0d52cddf0c889e79307d0d79220d84fb","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649388850.0.tgz","fileCount":14,"unpackedSize":27428673,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDDKdCwY6B4+lQbMBWl/WtXmGV5KqgC8KmRvj6JiunlVAiBKp2f3DA436oFSY1c2XTyRavYKFs+S8uKeMOMK4lQhXg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiT61PACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpwmw/+OFal7OgZWyysbtxAhBeYDEMwkSFnFElyYSNgB8obfR0mLOt1\r\ntSyEtPbamSF6GG7hgHP9/jdTOD3K131U8Tjk9QD3OoeyEDfO8MDfKbWCSlR9\r\nyQVP7QpcJce9TqrEfWq3zhEsuNeVNACIX6dV7VLXKgRXRlmpv1H1TmQODXj8\r\nquXImZbl4MJjUoefE2nsUjgjMQcQAGV3/4gmVhSKBovKiMlRJ0mbprgGm3/N\r\nNz/p3d8P5rCIlXA2cEpCWlhnzbYY+6EgE51PUo1vzKuX2+xjI0Vq4IgLUDpx\r\nEPvmoHOHqkODHFMfCMIlC7aQKerof2FVjrAzjXdDIXhVk1YO7k0zM1A8fYP5\r\nZj6jdLg/+mfLngpOFC8SLyvdpgLk+oVfMRnY8It5QOsTXHdHJ9HFNIeoNp6o\r\nA23cs4XQXvtlFqwBTuADuVnCw3Gye4ZseFXEMyLkoJrLYNIJlGMl/9SBQSJV\r\nIxt0cEFZ8oVgR1P+xIDUWENtzFGXHBPR73Aw3LV/hFtJzlhMJcXkMQ7TLhOi\r\nvRW1igqE8XXvyIQpgfUJZL5ZByUzb6HoVPQn/6/Dgd58KI5E1LvnmkVBRkes\r\n29YRLiHJt7NgB88S4GVY4F+7G0MBLZ4Bn23QbeqwJnyHmoAqhhD44z1gOsSX\r\nWfzecef1BBj+tMxj0YW1Lhupe+bRktKhHMM=\r\n=Xz/H\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649388850.0_1649388879528_0.9924438369680577"},"_hasShrinkwrap":false},"0.7.5-next-1649398416.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649398416.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649398416.0","@vuedx/projectconfig":"0.7.2-next-1649398416.0","@vuedx/shared":"0.7.4-next-1649398416.0","@vuedx/template-ast-types":"0.7.3-next-1649398416.0","@vuedx/vue-languageservice":"0.0.1-next-1649398416.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649398416.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"4cca358bcf99f2dc07de42b81d6389980125f6dd","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649398416.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-MVdYNe1Bo4QaRERyMDsRTT8XGo1VmLpOpSdzZ55F68wmuVBsRM3vrnT7IAfX5bTGk4soHvXisiDjkXhz7yk7ow==","shasum":"e5afd7f2b2dd147fa73e7df8027314927484e11b","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649398416.0.tgz","fileCount":14,"unpackedSize":27463433,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBKIerRnl6Zm/Z0FBuIOwp6aWuv1VPvgspJgvLo1VPraAiEA/WEaghHl1/wrMlneOG+tCAo3Vt+8a/6ybXRWvB7a3RI="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiT9KxACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo+rA/8C4B1X61hcMLf03EaFdxdSz1ozYwkZ8+bLAEmkDXtzn0bhCgT\r\nekLk2geq0GjinARALrQeWAtUEq0p3NfPmEqpZUb2je90tH9qDwxd9N+vphSf\r\nLJJnsK7jcX9t2ht5YZPGnj+zZfO8fiMrQ5vqIqy37gIUdEETteRQxujsP+K7\r\nnDs6Nw9lw7pExFfv47vexen/38GWRqxqJlfNoDz77dbvee8nRZMTaULRmNNc\r\noq+wl8nQibjyYK7v+67ajvCEs9RHLhN1wJC3+EjyWAFswuJQoWriFt/nsmEb\r\ntw69ZeYzZZtykPROgdTCJ8N4eJkrfe2dx7ynLdxBE0S6E3cN01uFH+1QHNIu\r\nbugf0T0/XWmAbAcoQWhAJ3lZV662fyrdhSZ1oQJRbag6AjPBK1e9087s1Rw5\r\nlc9SzMjdwrmW28kQmLTpWQub9LpOw6IDPvcn14JLXdWzqC+Lck4DGnXAN7QY\r\n+GTDK0LEB9Jm36eL43kLHTv2eIdf66lpKyeYFfDjrbgznPVCXjwTUo+eNehS\r\nj4MUeLAYHaV6pOWyRkoY1fub0hfrPznRUTZFkWHmTIdkCDqQao2KPPTfFxH/\r\n2Yt+kOIJG50olOQ0DwlNratYMaOHHeKJhR67oOYiuh5RnF6rnMgVTn3N0U8U\r\nTRtjLlBItJjlszc+K/DpBRztDBJ59razlHY=\r\n=cmG9\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649398416.0_1649398449236_0.1607469472719445"},"_hasShrinkwrap":false},"0.7.5-next-1649493814.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649493814.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649493814.0","@vuedx/projectconfig":"0.7.2-next-1649493814.0","@vuedx/shared":"0.7.4-next-1649493814.0","@vuedx/template-ast-types":"0.7.3-next-1649493814.0","@vuedx/vue-languageservice":"0.0.1-next-1649493814.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649493814.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"e1a2cf9ed858d4d2ca00f95fe8bcd0ecdd490296","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649493814.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-9jL8a2HuraOFxHpvo3vx764r22HD3cavTB5gTnQNsWf5FZq/C8uPuTTrvTHl0JTDk56rfe7PjvXB1G/UB+Svww==","shasum":"bd70666e8bbf631af770d884669842c13474e090","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649493814.0.tgz","fileCount":14,"unpackedSize":27480111,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCC3mugGFEC+n6fb7nV7cwIr1EzmMh7R8FvV/TN8wxjvAIgMoLT6Mt1veFNWTB1kxbySFQ02YSRcgyven2CgWVtKDQ="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUUdUACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo8oA//RWostYFXPO/WIGfB05y0O559v4aqEiOF6SNQp1g2KNTNtmPX\r\nl9iOkSgO+mlJ7B2ZrUsLd/1aMgEX+KHr9r8eglDstgETIGwNwUIFQuchSxc2\r\nqhZm7LHq65pBl2W1r5V/+Tg3spOPCWCbDGoO/2LTH6BcO37bh7hGMKTUh1Ys\r\n/o7DaFxV8+oNMz4bCiAC8oWIN01d37A1Uf1VfkMRLAmqSjtReSE/lzSjmS0e\r\nh668ENcYSPGQQUm3sPg9iygmaqYVYk2i8TYgZ1L2NU2DOsqsULvlM01And0G\r\nJ5/OQXuG4kmAFhph6CEWJbquOceRfGJd43MkhwN3Bb6UjOTicmaYcyGDSArE\r\nL02iNWWZSNDyfFVO35LzqKRVMSJ62rM4LV+0xcP5OIjsGUG7RJeEK2NQ7CRY\r\nEsTqGgkKlVIchwRBmEbwNy2uCstk7yyolZ+624AYopWSMY2bnSZfb7ZOxlpI\r\nuD4VYshwLhhCLiEa1sXJ6HktLSSzECpeM7cQci3Iezg2MW3UsCtSqYyLntCh\r\noqcn4ZNDW0Xl8A6huvxKX2jkq2mCEh9TCj6xdp353h6xCOb/7v9hg1lop25a\r\nLrWbsHzuHzQX44N6Bzkt8QOr4i+b9JkiCc1TwfxJUowU0kv577Yc9qzZ5IIK\r\nWWidYF3E5rKBXg4h5DVwX0UXEqeJ3MDVAmY=\r\n=13lL\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649493814.0_1649493843747_0.30539801903111363"},"_hasShrinkwrap":false},"0.7.5-next-1649577134.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649577134.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649577134.0","@vuedx/projectconfig":"0.7.2-next-1649577134.0","@vuedx/shared":"0.7.4-next-1649577134.0","@vuedx/template-ast-types":"0.7.3-next-1649577134.0","@vuedx/vue-languageservice":"0.0.1-next-1649577134.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649577134.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"2901f0410c6b9febaf51f16d7f76b572726fe2cd","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649577134.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-g3KGDZQidJZIUSu8kEsS2/v6l+AkuLAbGjPV4ZGO4enWIXlxxgHLvuw1GQcd7wFj3KrPHiv6RvGQkNlbQXnTBw==","shasum":"b78bb68fd6ea0d4e7670de696163acf94b910b7a","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649577134.0.tgz","fileCount":14,"unpackedSize":27513772,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD5geyFhlmFYnxHeyYtF3nIaERlqYXw3JjwH7DZE8cvZQIgAKVXwny+r+rXRvjo99rHLiLFgFd1jvvUYXdT2TOTMYs="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUozQACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqxnA//Vc/LDq7kg2t9snq+7RLAsxdv3FchDie/Z/7BAqsh5QfE+vDN\r\nXvkcb1yCCmNgAMtoryn/rB37uCA9o0Bv9Z4e+YjOtax0GrwjDI5NorvYBBXX\r\nQU37wXZouAaTYpKVYkUvtgjbtegA7ewlgEp9fU0y0cO+c6qgsIuT4i+UN/KU\r\nP2MTBliLUDAwNf6tGtKnxSpd3zOH5KudX7do/Ro8DVc8oI/YZz4Rqf2IgGrI\r\nEpqspbRW1XoU+byYz2ytps22qIJI3K6SvVTGGnEArWtXHery+7D1BWQkIV43\r\nl8C4pN/SfFHS1mgTeE/O69ic8vXmJEd57YBa6ooyKw/ILMpu+rvLFfm5JtZE\r\n8Rmlt0PWUPeC1f9OTvwIRvU9vdA5LyB7P4EV2535PX68/T2DCTq3pT9Tb8q6\r\n+8fZfjVed01zIRiAVdKFnz+re+Vje0Ph0Wfp4/ZCvRerVDsw9Ve74BP2m3ny\r\nIZO4cJFK1qycTVqxXxoBMwhcndzctqSMlWephXVID3rvJzzKL8fxAonE0Eh+\r\nlMW0JNvd6Rhal9TtnSWPIibj98dH14OvD1kX7HSGLJ1FRJKEqouQlJTa/UYf\r\nq17VI+WMbZLBX+f8NT85kzrZVgMR4XCSmW2qMGU6L4eMRACEwnCHvBhnw6mx\r\njEquoH8u/v5X4CHGqI8zOb8dHgyuRwd7qPw=\r\n=w5Iq\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649577134.0_1649577167867_0.6222154477239161"},"_hasShrinkwrap":false},"0.7.5-next-1649578076.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649578076.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649578076.0","@vuedx/projectconfig":"0.7.2-next-1649578076.0","@vuedx/shared":"0.7.4-next-1649578076.0","@vuedx/template-ast-types":"0.7.3-next-1649578076.0","@vuedx/vue-languageservice":"0.0.1-next-1649578076.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649578076.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"862ddfbff8577c943828631443decc6c07a6acf7","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649578076.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-h5chszgXafIsc2RRIZgtivjsEnSxO0HQt5yUGpoZUpnB6KAR8rr5+gBS/XrvcvQK8c4djY4d1LPO7MC83fU8MQ==","shasum":"7c1a859e8dc4dc3f2ae52f9caa3e0ab97f51f5f5","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649578076.0.tgz","fileCount":14,"unpackedSize":27513772,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICfOr4VNoqr5K5aTVMSLVMteVe26i/R0sTh+a3AUuIs5AiEAuW2hINoHHUFV3X2opdaKgDK6Pb5+dwFUfE/OeycK84U="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUpB7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpz5w//eCfj1hcLWH5nXLUU7nE/rt0TUin8/AZm48SUsfIomlJ70RkK\r\nfKhmbcAIbWtO+E4hZzwOlTgFHOoTDPdCFdOAp0JAjcJeZssAwSXkiq1CfWIz\r\nn/NIEvblsnWKn/zPKvDLCuOMWrptkeVtySN+eWAqdLxJ+G+e9GiAc4RLiFpS\r\n073aIOIvAHbPzVPpnv0NIL6XDoosn4m+VDj8/muNmRE3QLe487pCokj3xeRV\r\nqejSaxwm3lHsDtpuby0UWI365yIxUaDAA3kD8TQlNDG0+BR1hHP/RAVCLPcR\r\n2IrOQWr1PriohKO8Ibc1rMkcLydPedQ0wBgUtQ9MLZaSsCU1xuXep34ltqvk\r\nBis2WV9WOOG3Dn4g0OQZf3BIF6fYttazipmI9xEvVsZlWA5kiEQMeHq5YTRX\r\nyjbERhB+9i+m5SsqM0/jySnPfJiaIp8SbRN8hE6aQDXMm0/dmjgxREcrkxqo\r\n+afyNNYEmALqaHbASXHUynAE4S02hhpIKynPEUoVWqW7BsDIrximiQtB27YZ\r\nKwsdyB0gICLF14GfXQYr7/z2mBDQUKxrFOTaV8bXJ6nSW+Se7UJwQn645gsB\r\nSJIFP5/fr9Yq4ezZ+PtP86xluug8TRTrigAr/ZJJpd8F0QS1pBC9ocb4E9Pc\r\n/tOfGiwoTvoSknMoV1wnH+gP5dmKSoibwcM=\r\n=Xlq/\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649578076.0_1649578106676_0.051013040793286724"},"_hasShrinkwrap":false},"0.7.5-next-1649583602.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649583602.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649583602.0","@vuedx/projectconfig":"0.7.2-next-1649583602.0","@vuedx/shared":"0.7.4-next-1649583602.0","@vuedx/template-ast-types":"0.7.3-next-1649583602.0","@vuedx/vue-languageservice":"0.0.1-next-1649583602.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649583602.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"5f00d10baabc05084cc9543a38684d456a81fade","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649583602.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-jzQ2SpiFEMbz0Aie2QZ97DeDJQ6I7ylz4NIjsjUUwGRr/hYY1wDYB6NM5sJ6jmzvA9mpetIE3NTZdmlC0vwBjw==","shasum":"214dd01198377b32663c408a0998152fb2b0072a","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649583602.0.tgz","fileCount":14,"unpackedSize":27513772,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEE/rDWYUTobiPNU/Xw9bP3QnoluWjBlTiA6o5bnLpW3AiEA/o23qdfS6HSc2bcFACuTcRavRBxi7ekS6XC9JLjBmfs="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUqYRACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmph8xAAjEiofbaGrMeSVJaQXu3gClXwDiPY0bzsNhJamAqYkJ15oEF0\r\nTj554fNleM58UZrinGkSnd3ydMyheB38Ag+shPXkN0VO2OfrGizDEh+lw+iZ\r\nWmU3mPxviPkDd2+c1VALPDGtMaWdDPRhi4jnQXm6C7A3958q3XGIKou55Tuf\r\n58MkmIV8ppfU0coPobgzusZP+B04q7XdDgS81mKy4YqJ8ZHDMopjhKDCKVbP\r\nRQYRG6CYNbG1n72cQ6/HbB1VTcRelqs99QPOiQV6EKThTbCueRtBcfNbELi6\r\nxzQWmz2f3eM1n1eoVv7vZpFnIEx4kNY+SoiqGk/y98901DgZtvEVyGoPC+cT\r\nNWjjl55oco8FovNNyzrMuIeXEh3gbPCucBYqIJyT8aDGTd/GpTf0z2iBW1xV\r\nD5GDXkck25sTHFU2VHuhbKEVaqPhuupyIwBczdJhKIAMnyx2Gg7et36h3aSy\r\nlEI2Gdio1Npnsg0+q2nMf/A236NBAzae5q2tvQZTM5heF4s7VWHphf3v/rU9\r\ns325N0dYNOLopW2smsTCiK862hlxbVWVt/s4iwZZUFBHaq6QTUcVhySTti/B\r\nGppGLNqsBUj/DXnfWmfwFQiuWnStxs7BT8pljGqS9stKzG7DfXJHBQ30wTiL\r\n3XrqDJGw10rKxrSyc8gI2jKKBxLxMid+0LE=\r\n=WYIg\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649583602.0_1649583633384_0.9031285612910227"},"_hasShrinkwrap":false},"0.7.5-next-1649585554.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649585554.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649585554.0","@vuedx/projectconfig":"0.7.2-next-1649585554.0","@vuedx/shared":"0.7.4-next-1649585554.0","@vuedx/template-ast-types":"0.7.3-next-1649585554.0","@vuedx/vue-languageservice":"0.0.1-next-1649585554.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649585554.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n","readmeFilename":"readme.md","gitHead":"485440924b3d1acbfb86591a0b3c6683de22c45c","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649585554.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-CrrjubiCkpf5Y+rk6xMCGG5Tk/UTk9UHTN0I2bW6XFK9HDsQNW2gUeDD2Zsm3Sz2JUQpwYGVOkWKNmDqij7xqw==","shasum":"a078bd99d61612f0da766f5b46cd02ab5e37474d","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649585554.0.tgz","fileCount":14,"unpackedSize":27510866,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFWWre2vIiFbUpx/joKFoyhKgKWPt22DpG+kGuIhampSAiAO5pZhJCP+SpGE8BSfy4TzFZNrOU9t6iM9rfAlGOJc4w=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUq2wACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoQJw/+IvtdUdxtyhXZcPLdV2TLWmUVbazD9VOMcBAYvsPYAFcwSdi3\r\nK4BdEXaKCVFtoOSnEpSKFAAyPGQgI6QPrRGqvLMxKu0UHauZXaC+//N5qr1i\r\naDSVBI1utukuWtn8P0tS8mGT1dFV/+l9lxh4hXY/ArMb5KRlaVLfUa+rOZaf\r\nx9wfah+TPzNqLQQzwyVABERP5ORC03VdQ5iy0cj+N16/e9E1+LAPE2I4uSX/\r\nNHcha+0txoJ9cD45jM8cw48aUU2wyfgasSqixUGrnQnY3dbF30Xg2KQtc86a\r\n76js2XBQ8gpZ9hbXLQwPChpPUgOODWV+LrlzEJFdm/gsDhHZf3NRl1eiOCwR\r\n9Uuj4fjnVE78YqgrXGh79F7WoXWfxsb2KoBGmllfvQp4006075rFVuouywsi\r\nSiF503CzovrbqlWtN2+1FmWt3ixkPWT/Y6d4oed5tJyIR2ItfHOsjkXCNQsu\r\nbAWw97onCTltBxewO+vTzSdw8oRbaGxZ4m6UOmOMq3XN05ZwPoPAzKw8VXv7\r\nQtS9FFT6fj9zDLR80hSCoqziLbhAOiqqjMWMLVwi7klW8uqOm+te4kh7th1P\r\nqSrFmTFQs9vV3Y63neHwLj9W4Eggc/J0h//P+V+Gm5Pz2C8omAYgou37FxVE\r\n5Ccn48Lia0mz4MUbf8tBx+/ykwPzrURz5UM=\r\n=nngQ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649585554.0_1649585583947_0.6511388729288607"},"_hasShrinkwrap":false},"0.7.5-next-1649614433.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649614433.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649614433.0","@vuedx/projectconfig":"0.7.2-next-1649614433.0","@vuedx/shared":"0.7.4-next-1649614433.0","@vuedx/template-ast-types":"0.7.3-next-1649614433.0","@vuedx/vue-languageservice":"0.0.1-next-1649614433.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649614433.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"fbbe79ef98c900a696dc80ebbcb62a86f04fb193","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649614433.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-nNP1qQdiJDNuxIXXYGZkivHrR6iga9/3bF/aAo9vloL5rL0TVBiHnvn+ldjDi7ZjXD2NQXp/vo5rIw71jH7LwA==","shasum":"3d66471f1c5e771dfd3069f110288ecfa0acbb13","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649614433.0.tgz","fileCount":14,"unpackedSize":27511049,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDtpReUSZNuZPy3UUTuV7r3CeQHIB8+eTZv+SO/CWsZAAIgQk4PaFApnNx1nTQMI7DHM7gJ2IfTo06r3AuC5LE0QPw="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiUx59ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqMIhAAh7M6tC3q1LsM9XratASdSBQyDsQZI72fUosnLOt7bDgIAzQ3\r\nOYCqsh8eAQSKgHU6gYshXiZO305e/en/N1t/EYsxvXKO1du6lOGTIL+tDwUb\r\nbte+R8R77EpgRs5Y8oo5ORwX51kHO14wffWA4dRx3XeQAi/A8ZfJahBIicXP\r\nxM+wxOcxnQ64o4A5oxdi4wq82Klg6iN7oLl/Wb9jCoixU32gku9m9ezKswfc\r\nCnfcuKq4IIW6pgH7UKsoe3mF8yFd02LWex2m6mClwEjJDRs14sf25YoQsVct\r\nTQJbXezxEIfThxPMOlrarTAB1VXEb8sx9wHFq/j46sipWJp9CiB7vbVGfPaH\r\nLAiBKruymNCnVpmgD68V2YCkZPZ/HNYVIyWQ6D5ZFYmulTfz/6NBCm7coJ9R\r\nfs4bmWUi9SWTpLQ0UdAh5ARjVaZtE16HwiLsB80AHq0SUvrQbVPHDSqCPFPY\r\nU8G28O0efChoZEShtQJ1MXXVKdMz95SE/EOkKKsaAKo9JpwNxAMIcIXQgJv4\r\nn8Ge6TEw6kdqsIMnoiNwo7420jlv6wIn0xD6QqupTe7T0W6XrrPfzFioLrvw\r\nf1gxiCWzz28tZpzVS9t85PJ/r2EvHhZuTRY4bByGFpLj/rpOidNXzPEIeBfv\r\nAk6Vgy2S7R8ontlZ+HJqSALilDYZIfHCzJo=\r\n=6kox\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649614433.0_1649614461361_0.005692391371240779"},"_hasShrinkwrap":false},"0.7.5-next-1649653313.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649653313.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649653313.0","@vuedx/projectconfig":"0.7.2-next-1649653313.0","@vuedx/shared":"0.7.4-next-1649653313.0","@vuedx/template-ast-types":"0.7.3-next-1649653313.0","@vuedx/vue-languageservice":"0.0.1-next-1649653313.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649653313.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"e9ceb2483672608d6ab2dd096b85a07980744c68","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649653313.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-8jJP69HZU8g2675exYt7kD/d0NeoRvTf/5I/zVvV7dZ6jJgHb7wAXj1wHwgBVkpZy51R36Cm0YJLAIJqCyXTuA==","shasum":"152e55b560232827e33f22135a9c69690af708ba","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649653313.0.tgz","fileCount":14,"unpackedSize":27516245,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDHwXnrkrbXRn2yjovmrFHMhlEuNKaps39THoZo3C6y3QIhAMCcdvek8N7sdsiQMr3mjV3LocqQggXFXRjoabTMwRMk"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiU7ZhACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqS4g//c0mR8jDKTVbXTbXFVMfCEF7nxhPLSfrUvFs8Egf+vQHlmSiC\r\nBRZ0kT7pkHkiKrCny39cw7h43Tt3kXLPTK1VaQa2ttmkeVItsXricE5U2mwG\r\n5u9EJqJ8vC7VVU27n8i5oWFBHIvnJ94qHkvIP1JhI8iZByLfG8fHKqn9lfOX\r\nvIO7VHs9IIKQNV8gGjdkCAaWm1WlJlLghJcbxP/O0Poq8/ROAY2dRGQS72Zr\r\nqJiXfMpu/x7zYfMMtTyGbMk5fvpEZ1LRBYz7SqhX17hObgBegPOdeezNLILy\r\n0xew/M73xlETJpfGGANxkXXw+4kSJ8H0fT9idwbyk+/Uqj6El6KvgfPrVvuB\r\nC1U179fiQOU2GsjybZIIqsTlv3DR++6yx6wokk0QZ7YMr58lQ4UwhpkK37Iq\r\n0JNVAg4kRYjfGoPhMN9AC6f8zxpiYwud1u8TocR8HydvWtGUHUsiWfCJF/xm\r\nyU996wZKXItwqmx9MoHQKV8GO/mHLpeWt1+Q4xNWBkuCxgwTiRraVaRPl88G\r\ntH3BBE3uLSwCobdPJgkolArskkz9ffAVWtWJ4jSN6f75jSpjgnLw4zpX9vxg\r\nfgzq8gi4H6hooJBluKrJMYcHsa3E5eNl5q7btYL0I9utrqouF7qsCmb3QxnB\r\n/LPa63fdDqD+YBrxGQ0nspQjZ9K0jVpls8A=\r\n=m88/\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649653313.0_1649653345048_0.08322592866010514"},"_hasShrinkwrap":false},"0.7.5-next-1649654649.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649654649.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649654649.0","@vuedx/projectconfig":"0.7.2-next-1649654649.0","@vuedx/shared":"0.7.4-next-1649654649.0","@vuedx/template-ast-types":"0.7.3-next-1649654649.0","@vuedx/vue-languageservice":"0.0.1-next-1649654649.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649654649.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"baca2df0687f60ab044618375770329caf69b6b2","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649654649.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-brnqFx1zz9cTX1+lU9fmF6i2BBmw3X6P1faQW1BqpjWmN1xx4xrGSUkXne/LiDIY9plfGSqAjEOlfyMdl0rHyg==","shasum":"81e4c17f36afb71c433950a361bd174265c77b4e","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649654649.0.tgz","fileCount":14,"unpackedSize":27516245,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDdmf78Xl55pBerUfxffSogvns5F56cP1ZY3d2rU3WFXgIgSYW7Ks2eSQTLXr3Bq1yhfJ3TVlk9k+ifDnW8eYrwzwk="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiU7uVACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpT2g/+M5h27I59Sccu5xk2+7X7KLYAHX0BZgc6ftw16wlAXoiJjgnP\r\nPHC7+WDHWi185cCm2qcVIsdMawPquvyI/l13mckw6qjR7KlzmqQxYAOX4B5l\r\nqpTR7cJlLYA25PvAGrFYmTpaW2U2NgJq6fmzSweO3gEKC8/vaIcrRBKM3lYj\r\n7MCUZW3aLpvJFZAYvkaLExjh3XZ7qO6TE9xUL1AMhzmFSlRJrwzCb5aRVCTi\r\nbKkEDaSZaMS/Fwz0wpVNloDRZDNfjP+SEwhw/Pji+L2E+YDENV9AfpbFUWMp\r\nGk6EeYqgBD3oy9jMoTTwhlAxx8mQhOs8fung/gjPdQdPxOztrLs75kcsxASE\r\nx4OxJEL4dx7HH/taSIraM56s6ck+Oibca8tjJRvIjberMrI/Y+znOzt+2kzq\r\nYrr32A6iF2qqhQkdqG3MABWsRWQM4XHVdkRbr/IWesPPTOzl5FqODgDITqdT\r\nfdfJIngE8SS+pXy40D9WT4Mgsgq4ej9OmAeO6pWbcPqTSeNne/KyRf2ZsD/L\r\ny1+KS2/0F6Da3UVVE549iTQwqsiVhXr7tDt84wVmhNv1ygAKBA7gC7KlAyXc\r\n/ibjDElzLLHsqXHucXkIcaPfx3Iz5emsxF//hXrOdRyvijv4yV95OdvvGHx6\r\n8uuvqvoTdToVcHnlS4aoQLDHs6fdLA/efyk=\r\n=NOJ1\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649654649.0_1649654677664_0.14111493972973088"},"_hasShrinkwrap":false},"0.7.5-next-1649655181.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649655181.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649655181.0","@vuedx/projectconfig":"0.7.2-next-1649655181.0","@vuedx/shared":"0.7.4-next-1649655181.0","@vuedx/template-ast-types":"0.7.3-next-1649655181.0","@vuedx/vue-languageservice":"0.0.1-next-1649655181.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649655181.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"98f4a51c4e434d02292f17eeef73a7386581a54e","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649655181.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-9OMAuyMms24xNp6XZsjVLdJd+uu73yH3G0E1J0ct8Up2tRYS9ozfEcDNdWjQjlwMXVmxCPWLaBiuKLs6KdZB6Q==","shasum":"0a8b2a1c17fe12e53f915e84d7244c077b7780a7","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649655181.0.tgz","fileCount":14,"unpackedSize":27515681,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDEAhH1YLIvJX5gIuN9o5dXuk0Y4bNUgSC+RbAe6lu4jwIgYyzgcmmqEGsj2wVrs0AcEd+atATuklpufx7gcn7+udc="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiU72pACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp9Tw/9EEZ+Yvz1XCIdlfm8X2uPe5m+Y6Ey4GN9QNDeHsrVcF/a0Vge\r\nzsy0Eafa9evgJsEZayqi/E15x5m5BHPB1BM5FZICKmrO5UciY5XquL5wV0Ki\r\nZb33tOah46FMVBfVgIuO+ZQreN+nx4o5EUce3KuRwEBoRpQc3gjEcudD1cfn\r\n7DzBP03uHfyCwAOF1jnWmEeW0EyuSwQWn4tEwu+xAkMkgWobMlmLnvlIQ7y1\r\nVS4a09YzNRd/2JRiqKqqzbGa3fgYUEasfJMAedJ2ho2pGccf8WGpJJLsB7p+\r\n5gxOKgooRHJvyQAe0RN7fakMOMRSK55lM+rQhqNYXNs/RoR57nUlUqlG9xso\r\ndPC0bOQG9dCkrVwml/9Uk0/Ds5zaCYddlVi7fClf040/kvkKtGr2qBQXwfSQ\r\nxNA/bpL/3Ox071avqaMSPYMS7VNBe896HVAaWO/cmR5YnP+N5ZDYCH9Zd9mI\r\npZqbCwmZoeOSIO1azQ3ih4wUDUn3D8Ys125Ch0jrHOCLShLgXx6qyMdldj8m\r\nzEeBO/wsvzKFaxfieXRRb0LN1sC0bWEg7fdidQiozj1l6lr5PfXwyelEdMgJ\r\nZ2LMdQOdOUuO5sHPYl8lEOkwnUaf0KsvwHylGMNEgSaSR49abvszAdQworvt\r\nDX9tA9R16EUCMWyuBtNcXMC8pIUFkEHd+gU=\r\n=Nsv0\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649655181.0_1649655208878_0.6738476268109173"},"_hasShrinkwrap":false},"0.7.5-next-1649663515.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1649663515.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/index.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["vue","typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@intlify/core":"^9.0.0-beta.15","@vuedx/compiler-sfc":"0.7.2-next-1649663515.0","@vuedx/projectconfig":"0.7.2-next-1649663515.0","@vuedx/shared":"0.7.4-next-1649663515.0","@vuedx/template-ast-types":"0.7.3-next-1649663515.0","@vuedx/vue-languageservice":"0.0.1-next-1649663515.0","@vuedx/vue-virtual-textdocument":"0.7.5-next-1649663515.0","de-indent":"^1.0.2","json5":"^2.1.3","vscode-uri":"^2.1.2","vscode-web-custom-data":"^0.3.2"},"devDependencies":{"@vue/runtime-core":"^3.2.6","csstype":"^3.0.5","quick-lru":"^5.1.1","typescript":"^4.0.3","vscode-languageserver-textdocument":"^1.0.1","vue":"^3.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"b31056c4569b93df24c83d2b5a7721af50329584","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1649663515.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-BWiePIfIHiT2280f3XVrBShggh4zEMBYOf5eBuqTPEIJcLnxJP7S0cULgmKEMhfhpfi/8vuPNi6Ip/Nj11pzww==","shasum":"199eda1fbc591c35fcf212ac22871211ec7fd790","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1649663515.0.tgz","fileCount":14,"unpackedSize":27518323,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCmGLrJ0/b1FnWPaFtwM1AOHpaJlCJKEfVA7jjZxLv2MwIgWOAo6zaoR2Brv+UIC3GC8hPGgFWWYHtDcAnNyYZC3Zw="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiU945ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpBjg/8Dgl+j2lHU2J4e/Fzxw7hzketkS0zm9IvVhmkL6z1G+TCGT+V\r\nXWzOXEhsj/4HYv4FlEQkoH4vQupTfUjV1QmVRd2/k0akCfhF0VMJhdFZB+XP\r\nt6HD06j0J/Z+aJW/kDvi4dnQ5LrkzhB3Uqij1WKnIhnj1++lO330qG2u+5/O\r\njXerwQcbjBjQN/Y/EfA/j2hMRDuGcS+eAjUSBQoaIFlg7IEbKD/dA/45EqvU\r\nLKVQKBb/vy7/ugEsrz7cCaeAOyqp1ah3YkJlefT9gyar4YTQcqGsRt0Hi0xa\r\n9Shlk6JtRyWdr0hdWIWkmsO4+vCPFHK17AGBuclriMlMVgAGuLRIdI189ivi\r\nq4A96hh73t8i0uNrA3nA61kLPtWNystcXp58/OiAUYlA5eJzEP2DIhteg6Ga\r\nvm9nrOR+eYCe3g1m5792PNKAbgVNaqAYZ8hWwFQzRFkm585oX5UdR8Bl6zfd\r\nvtI6LX2XCxykbqFiYZpf1fNa3IvVKhNtsftx7nVAWqcSTuO1ippj73jtqRor\r\nqAAShYEB2QxYVXoeXIXjginOsa/T+SFZBz6c0400hBvgXURFY5aRqBXybbiM\r\n+sRulN3ON7//WXqxH9vjXzUnSmQc92bIvdpPubf9MLGHqMhxOYtpRrSK3biH\r\nzV8AEaO14JHwLHQE2efIlJl53jq2Vf8837w=\r\n=DBb8\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1649663515.0_1649663545267_0.9824577861420702"},"_hasShrinkwrap":false},"0.7.5-next-1650753481.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5-next-1650753481.0","description":"TypeScript plugin for Vue","main":"lib/standalone.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts","main":"lib/standalone.js","module":"lib/standalone.mjs"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["typescript","typescript/lib/tsserverlibrary","@vuedx/shared","@vuedx/vue-languageservice"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{},"devDependencies":{"@vuedx/shared":"0.7.4-next-1650753481.0","@vuedx/vue-languageservice":"0.0.1-next-1650753481.0","typescript":"^4.6.3"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"6aaeb32bce996ceed070c9f502b68d1e98f02bb8","_id":"@vuedx/typescript-plugin-vue@0.7.5-next-1650753481.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-yUHntC6Z32RY+ztzD9NT6QlXIqaKIy33DFDWUcoRMIxK+YyC00a0EVIbLZleOXLIFhKs3RnFV9siGePHCgU2fQ==","shasum":"5468353f2aa81eafaece9d10234ea1809058ddf6","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5-next-1650753481.0.tgz","fileCount":13,"unpackedSize":28337822,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEFozCJDRHYVbXt5gf3prBXq7BRufuanbun+8NN2OD1hAiBpIGvzLDN/4MyhCsbzVX2MLNOefoWtKaEZZS241+/K9A=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiZH/kACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqUqw/6AgjPj3YChg+6CWw0D0dZEBm8/yfxLTtSo/nYiOphtV89+f5h\r\n+88VtGp1/gwHnDQg73z7HgSNvlgm0wiB3Z6bjJww2GDPhD9xZ/py/3VFlGt/\r\nv3amdNIa1J1xOkTzMdHArwX24THtSs4nDYg0mPPOGkj51xZvoaOWL7YfhZKJ\r\n6AQ/Uqf/y85ZXDKzWKa2Pp5FLolta+8lfV4tuHmQPi2JhAqdN27bqCuFP5iG\r\nacvie5mAY5FUEb7dMw/9Zlf7XnKvxHAFPQFArLwsed80TLghuVSTIcpeOBKn\r\n4GF1PfusC/YM8WYgcMpAY9C4Ane3CVM/Awa998pc8FhRM0WjuHAbT3lOLLJS\r\nE5f4buJ3mrYBhfzKtvdVk8g9lYL/qDAkZe1bbZK9VSryPMnw4Z4ij7kog2MI\r\ndXLbIrsQB7fCcGAMm23LQorxXdppa593TTdZxyBaMudfCpQuiTRqnFMn9L6E\r\nxoiOsUgZlSrR/6oZKtfJBwF6ZFxYShkIU5CnCYLEH1NfRzxWzgHgcv3jSkY6\r\n2zem5aCuHfpIsxFG1SavK+sLNT5UpseKpl6uJqZIY+rYK6Cd4cKqJMf8v76N\r\nlaCLTY0wclHs+35HnyotmjcU+hnFLhcOj/wXdbv2VA8Xr2fuzFiQVam+Oikx\r\nTdJSnvk0dV5TkMMsLcP7FNnH1VrDLlqVbHE=\r\n=T7EX\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5-next-1650753481.0_1650753508295_0.8772576832474253"},"_hasShrinkwrap":false},"0.7.5":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.5","description":"TypeScript plugin for Vue","main":"lib/standalone.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts","main":"lib/standalone.js","module":"lib/standalone.mjs"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["typescript","typescript/lib/tsserverlibrary","@vuedx/shared","@vuedx/vue-languageservice"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{},"devDependencies":{"@vuedx/shared":"0.7.4","@vuedx/vue-languageservice":"0.0.1","typescript":"^4.6.3"},"gitHead":"1170cbb518ca173bd35f06f1a435b9be5ded6603","_id":"@vuedx/typescript-plugin-vue@0.7.5","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-HHx0cOP3wGy5ELxgAd/w4HUH2xbWbppr5LVD8DtU76l1eYUAPqKkFHASPJMmExHXY9ufIcv7nHiNhwq0FbSd+Q==","shasum":"60ee456d21f7378b6f7d69cf87b0d5076bf33d6f","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.5.tgz","fileCount":13,"unpackedSize":28337768,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDLLPKlKbDMt3tzcbtJGEIarCKyRTKsW3q+YMgpoeQSnwIgXhrTLmrh3oKxADNF495G8n2xdP++nZXum6vnh183v2E="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiaPOwACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqeXQ/9Hq3EdhwRZmKZkt/OQ3AIhdd1Q+f/HQqQwuEOIvpWSpQj59y3\r\n+dWLXzLk5iJEGIkE9em4RWfrf/WQzRFxXLj6jDd1jSIvJlAbt8pPZ6dV0zHS\r\nrgEINyEwA7AhTSfopWqSjdT03GajUrk+95oaHqfKDT1vs+maTBHY4sBX46B5\r\nqai+sFCTCXbl11CoPN1uVfV/IqxbNqlhIooTHAs6UXgix6Fg2U5qBpYbIA9i\r\nr7+VydSpbLEF+TwL70G0fxxpM6VpwHP3B95DF+G3c/AZVffztRn62wvcIPJv\r\nHrTvY+Xg7ykrZ50O9JlBrMxBcNRzCtvXOzI2eMYvKabtc954V/BeJZWxIM+W\r\ndyLlZ6yRyCa7KUWrPJDVjEKsgL2X5WfGJBkIECWMPwYevYJCNrn+tc+9uSlC\r\nXRBzprAEeLwmM04zo6yd0XACpC3xVau7cem24DkKdlnzYTuKlabluhfwUkai\r\nsn2b2XH1QooICIsMqEcjsgL6UvxczBEKUK7SVP863/rnZ+ixqW799n++M5dK\r\nqCIAVndPKLY3jzE7ZXCuFLy9cqK9uIgUbzLdUS13GfMDd2fxFo10sS82hM2/\r\n/5JZFOsZxvwq5KYTt5gHEV8A+t3top7xToa1SSfSdR50wlcmljmTbioWnvFQ\r\nXY+ZHoCjIdwceVqk8vVOObOyo07N7bKgJyc=\r\n=8QKm\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.5_1651045296325_0.21130410650426712"},"_hasShrinkwrap":false},"0.7.6-next-1651048177.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1651048177.0","description":"TypeScript plugin for Vue","main":"lib/standalone.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts","main":"lib/standalone.js","module":"lib/standalone.mjs"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["typescript","typescript/lib/tsserverlibrary","@vuedx/shared","@vuedx/vue-languageservice"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{},"devDependencies":{"@vuedx/shared":"0.7.5-next-1651048177.0","@vuedx/vue-languageservice":"0.0.2-next-1651048177.0","typescript":"^4.6.3"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"186462361e96f4ea70f43e4086d2c07d509d2762","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1651048177.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-QmFzzm1z480cuvnTd/9I7y8ganY2n7VbMNjIb42RaeJi63gd5KheuPDQc7tiWmeSqCSn8jx3i0HH3u7Z4+PdDw==","shasum":"50303f87b13140a3117cd9ea6dc069dccc6bf2bd","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1651048177.0.tgz","fileCount":13,"unpackedSize":28337822,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCdm483682BealTClFe/jc/8AkALdn5RXNlE/udr09NEwIgaqFyK2nW0Rcj7U+U0bb2OWeO6W8dGvPT5lCqiBT/Qhg="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiaP8RACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmplUBAAiOoQ3CO0eLtdeiSU6Rdum71D3ytFNaPWHeRyhWV5ukRyuPPN\r\nmeKtIeRsTAPTBu0ujXMltglU/jXHd/8iejIu17x0J5X3876HYQvmcXDjLpKF\r\nGnI5d5jZjvJv/erT8gGDfG3UqVcMQU2AyvjDif0HCbpfIWdgl9njRInKzWCR\r\nQa8tO6/e6aSjdLXY8yRc7bGAmcsrDxgBDHMLcPuzMahEEt+c+kRoxc/k21x0\r\nDfyPviC2DtFoyYkeCcFPHFooiVYtGCcqow+bOHe74JdKji1LdmwjaL0HN9HB\r\n7MpPOrw0BEnQuvv2xAy0appLDx0aZE1E2AvAJYst1PVRGny0T68uIeJbZv6t\r\nSZlbfHxUhLefjwc8o3nCw/BZfO9yAPuSz4Oq1HpHcs+5dDH0xR2JFTxsKYx+\r\nBXXpkPVMEiLyNYqemrrVpBUWoqfesl9/X2WkPRwCKbOucg8fcx0X9sxFdEOZ\r\nkjQTug8q463Qm1TXuzfCDP4Oe26lcTU6y0g++knauikUANZMHFY464FyxBL4\r\n144YqpPqIElJmUyqPckehlgUtHugb4pshMQwYTd761VrfiPfI1/SGDknwXNG\r\nOKkThZDgrbDig6+1ttyTGKrs9HDcxogB/WH2Kuefc6QwYxXOisKDRTPghFMX\r\nBok3dej61KLNHc7Kk8ea+HfGI5lQZfTpz44=\r\n=+w/k\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1651048177.0_1651048209209_0.4283127768685344"},"_hasShrinkwrap":false},"0.7.6-next-1651050089.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1651050089.0","description":"TypeScript plugin for Vue","main":"lib/standalone.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts","main":"lib/standalone.js","module":"lib/standalone.mjs"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/index.js","exports":"default"},{"format":"module","file":"lib/index.mjs","exports":"named"},{"format":"commonjs","file":"lib/standalone.js","exports":"default","bundle":true},{"format":"module","file":"lib/standalone.mjs","exports":"named","bundle":true}]},"external":["typescript","typescript/lib/tsserverlibrary","@vuedx/shared","@vuedx/vue-languageservice"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{},"devDependencies":{"@vuedx/shared":"0.7.5-next-1651050089.0","@vuedx/vue-languageservice":"0.0.2-next-1651050089.0","typescript":"^4.6.3"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"c9c96436e9bafe3c5213fb7fbcf5dde9e5b56f44","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1651050089.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-T58wPELrdp1QzydizZ+rrl6ep8VzqcdBiOA43ox8cfkVNuc7Wf3veTZ9P1xpcJk35crYb4dhPvJtGUe9IogdCA==","shasum":"263d416321a8a19eb5675f3a5f1f6e77fe46cebb","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1651050089.0.tgz","fileCount":13,"unpackedSize":28337822,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEvZjUxYKrSInhdGAwuAyFwWBLNkHEJCUMrT1X9eM2g7AiByXltdW8KTBQjiunAk1J0DV0hg7l2zHNH0pQHKw8ULXA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiaQaGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoWOg/9ErvJ9U0N/g0c2SNpYpJ6qwDAdDREsEKe3nuouxJIUoGLH4AW\r\n8tf/SKg9Rn+JKTe11ZwAqeEyn9Z0Wfuw9Q4ZE1lmCSA1gsspYnXPQw428NJL\r\nw9WguxC5KoN91dcEQ82p3uSrL+c1KT4O51iZu73gpp/52woyPxXyIECDLA+r\r\nx1EuMVclRDeATYQBrT5QkbJux+LmjxothQH/u7XPC9MJQgSR2R5R8tUt9vC4\r\nDvL2LVoMzvVa5q5gEzCwlir9e0yOimZW25PxS7hrmuTRWWCpnooFEftt8QYU\r\nVoDZt56Acprk19zZnCTOWZeLyUmUIhNYdT2/ynnxtnHOO04YxifxjGSRRLmF\r\nspejnXq5Wh8akBHx3uISTe1i0ky51H9RHYTAr0dPPWpwcSJQpeje5omGiMS6\r\npcA/kSH4u6CpaSYfl6Jrl7Pp92T4OKzKd26rXmoEH+DaLLRfD/eWWeR7hpcz\r\nbPB3lw5b0otKaCb6mDKBzA7TKUzwu+P22dkebcfvYGLnf6enh1/+I+SHm+v2\r\nRN89AFL5tvqxMVuxNQ7WWrGGoD5Gjjp5tG0GKqIyYWxKTeq/+bHejWrBMxkx\r\n87y+D4Cd8tBenmARbrqpbg/LYD28MbYnzRvcIvcOMEbVAflSoyDuNs7CzQ+A\r\nEFPMIA72jDaA7kVFd74RMgrfc/IN9xjyBQ0=\r\n=NLRi\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1651050089.0_1651050117686_0.9213461218290844"},"_hasShrinkwrap":false},"0.7.6-next-1651055813.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1651055813.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","publishConfig":{"types":"lib/index.d.ts"},"buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"dts","file":"lib/index.d.ts"},{"format":"commonjs","file":"lib/standalone.js","bundle":true},{"format":"module","file":"lib/standalone.mjs","bundle":true}]},"external":["typescript","typescript/lib/tsserverlibrary","@vuedx/shared","@vuedx/vue-languageservice"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{},"devDependencies":{"@vuedx/shared":"0.7.5-next-1651055813.0","@vuedx/vue-languageservice":"0.0.2-next-1651055813.0","typescript":"^4.6.3"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","gitHead":"1dc57633847dd68a03fd05e79bc031dabf3b9085","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1651055813.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-LH3/hnWdZjuvYslxIJEkYhmw5aJMnxAqjOKXF1Xc+h997lhpZDtZLP/0P/1amSJb2PBkbBzKQ66FpxfjAzmIwQ==","shasum":"2501de76b0e18a379b8e23f98b78e9a4b86578ff","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1651055813.0.tgz","fileCount":10,"unpackedSize":22463839,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB8zvRpA/48EtKMZKZMsdk3hsT2Azjwk9aHxRx2EXyHeAiBYMPNjBxNT81z4V3w+OHQ1l/aBDoy2I0R5+ptA/MCPGg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiaRztACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmodoRAAoucLlv0YFPOtG4ZW0uSGKZLq4OlxSXJ6K/t3kPf3jdHLlyqn\r\nXVSTQt+Kk8I5Y5zfrtKcpOpzn7xaJH7SeshEtllGGaUOhH+X4T1j6JTVedq/\r\nbYQ4I0xhogYDYKtPmxjqJGnqq2Twx35OhLC4V84be6hgw8VsaXjmelgUlChX\r\nR6A/rjsNVVdX7mU2ZU+ii38ER+lDtXRohsLU/JI3futbVHi3wY5pPPUZ0CQv\r\nDgtohEgbiZXb/rRI3FGDqVQSAFcxmyMeJxOoCKkJbDT2cP9y41MyXV6YWqBu\r\nf/7p3LXwpYuE95NzZ5zHF8bRhksO+zxxr9ucCuFWPSPQisf5cbs2FIf+l32p\r\n6TTFmV7hocSBmsJl1fN76xQ4RqIwmGT0CrfyZZ2H+R/n6Ny1ONzL9eGqp1vn\r\njHBdXoPdW9gJCH7gDcxfVIqHh9ggLkpOMzHnX7OTWwUgi0B0XvkG9pWFQuYr\r\n76ad9x1t/CeIoHZ1ScJG0Vif01L11u8b7ReyxJro6V1IkzfUR9n8xnPq1Pld\r\nykOld2Lxs76Rk5jlOQBGICKJLAdlWvNL6eKQZNbJvklKNh/ugtHNeCzkLXz8\r\ntwD8tdkvjkwPsjb7fLpMYMnP+BmmVNqOuCeFhZDkvbL7fbAHuaE3KhyoPGmj\r\ne9XWTnXi25bkK0q+nCtbdS39I3C10oDN2qg=\r\n=jFpE\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1651055813.0_1651055852982_0.8595947798217485"},"_hasShrinkwrap":false},"0.7.6-next-1663917928.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1663917928.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/shared":"0.7.5-next-1663917928.0","@vuedx/vue-languageservice":"0.0.2-next-1663917928.0"},"devDependencies":{"typescript":"^4.6.3"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1663917928.0","_integrity":"sha512-zi8/SxDRqxTY0dCIKN62mkwuv4dlmz/IKpsvd7tak1qWiA9eDQ1jOT5k8zdyt373XgcCY4dJb2P+nxlk2m+prw==","_resolved":"/tmp/32ed0fcd92db0a96183614ecd582017a/vuedx-typescript-plugin-vue-0.7.6-next-1663917928.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1663917928.0.tgz","_nodeVersion":"18.9.0","_npmVersion":"8.19.1","dist":{"integrity":"sha512-zi8/SxDRqxTY0dCIKN62mkwuv4dlmz/IKpsvd7tak1qWiA9eDQ1jOT5k8zdyt373XgcCY4dJb2P+nxlk2m+prw==","shasum":"6bb7c75673b5f9d2e3b81c26126d2cbcf2a7db80","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1663917928.0.tgz","fileCount":16,"unpackedSize":39382755,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCX0ZejMIsT1GSKJ4tJgydLmt1Pv+/MbHLSjwObF0+WdAIgJ9/PEhVsDBj3TI7UnAAsA7LMeKutih8Z+jTPwGVW8Ew="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjLV+KACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpW6BAAkGZgGGMGfnG/NPHGhYF54ZtOJwha+BR9eYGUsVgppg5V9bX1\r\nHbKM1qJEdrzRvTx76liE2UZMlzCmk1cYoLyCG+1g9618k6a8l25visVmKieu\r\nkb0A9vgVFyNn23XI6o5Xn0QwHCSA/0u/1dN3rnPFFgRQ5x+NaZosG+Cfr0Yf\r\nXahofK7hJ9K+EqZuPStiDF67MJDFxQi507ekMXXOXtsvkCw0tgVtasiIouLs\r\ny5dSdUqRgRGD0N+NYwxBv3zS1Ckm3h9y2enVsb36g1DM5AxqiK5sb7YgkKF2\r\nNnH47ej6JN4kGDyx6YW/ZEqqrSXlFSNgFxM41oXZezGeZyoTD/nUP9XQKcxa\r\nCbMibLjwEnLmZ5rnhu9yNNKmPQoZM1ZIIuvSal0wHS2XCt2KCFJBQkVOukoT\r\nqcZhGHNffTrXnqMS38KY/9y6WGl6d/CO3tzXScOf3kK4kcP9IvCeQ6RMGDEt\r\nmm53hswWchMljp9qa1jLQGDlEpBJMEnAb6miDa7ieVPWHXOLk7ZAMwzh47eG\r\ntxkRrdO9smgNMog7rFGZ415E8WW1PXKFzpD4qPacq4PCG/VSqNMNqVjqZQYe\r\nPUNL72pzcPugUlq5/4lcXOZqJPdRthEOl15UsvTIYXSfaKm695gIHtu2YckN\r\ndKb97NK6dOscM1Ol9tiij9FHCu6d1WgSH9w=\r\n=ql05\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1663917928.0_1663917961307_0.6538345654073425"},"_hasShrinkwrap":false},"0.7.6-next-1663918844.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1663918844.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/shared":"0.7.5-next-1663918844.0","@vuedx/vue-languageservice":"0.0.2-next-1663918844.0"},"devDependencies":{"typescript":"^4.6.3"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1663918844.0","_integrity":"sha512-D6Z4FKIyehx2dWMWcZZ2SbB4bP4W/4OozCR/qbajo333au4oPkThTBEbTw+90G9/DJqEs2afc37KNSRWqyhKaw==","_resolved":"/tmp/2097ef4224159045c4ea0ccfadf098b2/vuedx-typescript-plugin-vue-0.7.6-next-1663918844.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1663918844.0.tgz","_nodeVersion":"18.9.0","_npmVersion":"8.19.1","dist":{"integrity":"sha512-D6Z4FKIyehx2dWMWcZZ2SbB4bP4W/4OozCR/qbajo333au4oPkThTBEbTw+90G9/DJqEs2afc37KNSRWqyhKaw==","shasum":"3a52a5df028db49100e7a1852f48df78d6914530","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1663918844.0.tgz","fileCount":16,"unpackedSize":39382755,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICVwvBHmAu/SCOUkorNf3JxtWLSlcoV11U4HUGyeTgXsAiEAvna4w3PXFA5akJvV6Suc1K1qzL3FZzPQ2zA3zTYzo4g="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjLWMjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr8iw/+IdJxA3rx6NizquEOdXkSimbwRABAXCYhi9Fqea5BNMGUzu64\r\naWV4i3wiOcNHeTU5kITfChlJLrVIQ6pWxKo52a3NZB3m4fMGv5ZEJbb8MRFH\r\nfklfOCUMeW3R6q1dZ6xFIXILKDJNhQ6q77OEWiP4jik0B6PQWVCzRh/6biTM\r\nvQcAMpeHwvumTOl+5l3oj3qWIej2CE62ABKSPhddZRroTuz09MhVSMhtf+N/\r\nWINfgnoFYUaJTiumSxWIrU5qrb1NEmyvCt0QWWPeR0rXuT+MBnquTrU++5JZ\r\nKCwqRTGdQrPlhYNps4Kq+sHZjOMhVND4L/5CLR876Z/lGD3EKPJ6EH/7akX+\r\nkslyLU55zR9s4jYuHrxwxeSJHtubS7NZyiI2l0wz8RE2zCTl0UK66dXfh+dj\r\n0PTMNQAND68/MwJBzyRAuzww+VPo2Vz/81P3Qwd/S2QqGu9UAO5PyYjrcm3e\r\numKfpURXSPjoS0LLkxC+fUfmH3pVIn/LUfrlDwkrrt9yN+dChJ4w49Mdn8N0\r\nk/X7HLOxDt3NTdT7BeRzWTpHwY53Kc0LgRtgA826fatF6V3+WsDhTsPaeBxE\r\nPpNbq2DwHd7h8SSuGCv40htHItTNfVPYmWhxZe/68oblYaeI9y72eYbIoq9n\r\netkXdJy47IhU9klzQH6CQhtQG2qc3YL77HA=\r\n=0LJH\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1663918844.0_1663918883068_0.527899448540246"},"_hasShrinkwrap":false},"0.7.6-next-1664761915.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1664761915.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/shared":"0.7.5-next-1664761915.0","@vuedx/vue-languageservice":"0.0.2-next-1664761915.0"},"devDependencies":{"typescript":"^4.6.3"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1664761915.0","_integrity":"sha512-dDtfGMdSsxRjkTQgddHlZ/hWi+ipfAF7bAEQKY1eYtU9rG64ptvfSxZ9QUl2o/tfZ6DPGaATkTWYvRWvAYswNw==","_resolved":"/tmp/6ab75fbd715df64dfe0b12b11fe6d94b/vuedx-typescript-plugin-vue-0.7.6-next-1664761915.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1664761915.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-dDtfGMdSsxRjkTQgddHlZ/hWi+ipfAF7bAEQKY1eYtU9rG64ptvfSxZ9QUl2o/tfZ6DPGaATkTWYvRWvAYswNw==","shasum":"d6f79e26e3b527b36396dfd80bfe3d00486c8df4","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1664761915.0.tgz","fileCount":16,"unpackedSize":28653021,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFHi2jCkLsyvHNo3TH0AhOGgqu4uBy73KSBtq+g+90X6AiEAuhVKKnKCNmSkTIpmBZ+SNu3onMCrS978oVAGiLYW7Qo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjOkBeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq7OQ/7BIg6aj9rJCKiISt+8e6Vn6gGqPhZQx6VZZU7efqZne7fLCgf\r\ng6kwfrvhPN0Uz5TlqC1mQNCOD6GPvtHHjaycvNWUVdOHVxSRN+9F68mcWvDn\r\nZZyVkJbpFZhFWUEUoJE17BcoBZrUgK+dS4+SOAXVDhMhGJvJ6tBcEIRGG+E4\r\nOaB0mnwPPKKbxgJ/nfbtzpsB5X9CnaFx0+0OD0M7G9xMoTSh1D6T5Mxhnlyd\r\n5OnLZCSGF66j7iGJKQbPUobF9Sz5PZ6bhA2QiZ3/fbFXdIuFD/n0FJxI7qYo\r\nWUVC9Q6s1F4xT0MgH2CuL81pnj5Y/2sxzHfjYRLsU2zEVWjgPZGk+lE+OPxD\r\ny/+ZB60Ec57o/Tnv6BcHzGOtokkxSQWemA1Frla13rYD4trIAjT/D9L4chrv\r\nOtiKMFVBESarWMqe9fgsk/VoYQdhkYiNJaxSBpbq4kS4uIWLzfXfrskvaIAW\r\n5W1e2DOCXUYYoOEEFHGmaA5X8LL1fkybuMDs9Kc04oklShpXU84ZwaQV+dOm\r\nPvQT1MRQUJ9eNYjV//sNvkv5Aj+KDmnOWV2Gfdk+3kjh1TbnxeL7s8bmuhGF\r\nxXoM/nofr/i2gSzjeCqn/pMCJXoVhzTPK9Ze70BiCtitzpv7qYJaar9okbCr\r\ntWAAkfi76hwvXFFHIkOHKHuWb1Xgh6nzPhQ=\r\n=zNRt\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1664761915.0_1664761950561_0.20036491337668494"},"_hasShrinkwrap":false},"0.7.6-next-1664775821.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1664775821.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1664775821.0","@vuedx/shared":"0.7.5-next-1664775821.0","@vuedx/template-ast-types":"0.7.4-next-1664775821.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1664775821.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1664775821.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1664775821.0","_integrity":"sha512-SxvkYTd5EYAI5ryiF4CU7p5TP8dayp4sNhGiAg3gzS2WbXaI9jTeMjclwWdAglXazn29i93UyknGPEkx9A4rcw==","_resolved":"/tmp/a84747ed861ad958e0629f148904b233/vuedx-typescript-plugin-vue-0.7.6-next-1664775821.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1664775821.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-SxvkYTd5EYAI5ryiF4CU7p5TP8dayp4sNhGiAg3gzS2WbXaI9jTeMjclwWdAglXazn29i93UyknGPEkx9A4rcw==","shasum":"5407790b8eb94b130a3df29cc1a18714f32d0af5","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1664775821.0.tgz","fileCount":110,"unpackedSize":20201370,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDqzoLRinlMEQm2hM4bOPJzvQsJi+BtdAIsPRv1W/n3owIgTf5RV+MWZbc30HUnK9thzjzswOPWpQ+5MXVqBpuFeoo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjOnapACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoz6Q/+ICCXGaSXV1JJmXRkBA8n98aoxadtzBSghcxy7IG8X4PRv/M8\r\nCv6RAnDac0Qp9uNBktXYZhhTQo0uA/QjFFKp2uIc4Q1DkLCQwxIi5gsUaBnT\r\nkqSxlV7WeDoewQI/jDYLVa5F+DsaNNlISVK8Il9QDPboiBON74eYW0U4B4Mg\r\nOgWP8IUxdCBwCHOGnL/ZHDhScImBLZaxyE9M/uIY9CKVggk40AJ1tRx4h2of\r\n1zIvs3+ogUh8KtjE2aApMNz2MgbFPskw7gujw2NAiIwvfyXcFyWYI3JbkOvd\r\nU0CaoXfZWuvmibCyuOjQ/8iGDowndq1cmyCqQrbkVPXaroOxY/LjpgbPfVnn\r\nZnkoMK+ejn9esH3tyk3aFAWxQOWwqMBXV26bRBSzaDpoQ4B2B/+erBHcatLW\r\nNnB0jmimkMrxKAalFAUc5JcccrAlLweYUSZvjbQ7t8YqGY/7Ol636pTp3kwc\r\nGYDD/DPcqNbL2PLcXw65L3rOy774v8sK4yGt94FfTacLTxkP1uSYDPAWctpP\r\nO44cnoDRKe8VHFjlwz9HkkqflM+PQwAT0EAsu22HGBnx/e1mLX6kci7rTM7w\r\nAF2XB7EfJB5S0O2eMo4/ePgIp/cx7Sz9WxM4epxuKsba6hR4XUCJIJsI1UoJ\r\nmWQLEXyLzLhW5fmz3h6iB74UJ6uisgW3GMk=\r\n=LuzH\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1664775821.0_1664775849460_0.40667058283330326"},"_hasShrinkwrap":false},"0.7.6-next-1664852417.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1664852417.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1664852417.0","@vuedx/shared":"0.7.5-next-1664852417.0","@vuedx/template-ast-types":"0.7.4-next-1664852417.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1664852417.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1664852417.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1664852417.0","_integrity":"sha512-75VHK+IyZHoAZNoaCLYBtddb58mbS5KBKTFKgHV25NZfIRSRmCg9b8+Xc5YUC31kblQ1LkJzl/hyIUeUJ9w8sA==","_resolved":"/tmp/707a060414dfdf2e53a496644cebfa27/vuedx-typescript-plugin-vue-0.7.6-next-1664852417.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1664852417.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-75VHK+IyZHoAZNoaCLYBtddb58mbS5KBKTFKgHV25NZfIRSRmCg9b8+Xc5YUC31kblQ1LkJzl/hyIUeUJ9w8sA==","shasum":"8d42f5bbeafb54a2528be8d6efe10d82d2482e89","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1664852417.0.tgz","fileCount":110,"unpackedSize":20259287,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICESUKam2zSMHnYDEdcEkPeP+weSSGSJ1wZHzpnA+4zDAiEAx9zcQIml4mFPR3nw1mJ+8Yh3RSDJWx5PQxXzTHWnHUY="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjO6HqACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrdtQ/7BsLSGHZ9xf9QRxqAkIH1SRlGJI+enVvjXR4/kDvqeRFpGI6a\r\nZbMcZMbR25ounaQ5ebxqCY7zJ5r5PmZAyBP+R3g1UmKlv4BqkgeEwxRE9fs9\r\n9r+/2pZF5/+Pq8j33nwaOSK/1W/LZI5W5KMm275cD/2ZBjbsjAcOpFPEBh0/\r\nmt74uxTY25Fx65uCOrmwzq4T1CCi7MRzcqeFwLZZOsFGa1QfTxrwvYH13k8q\r\n3kwU70cIyZmf6KhFSDC6mycO1zUxzIrxYbanJvgZ4CbSF4qVHufsyIj6ayb1\r\nxLoVHAG+9OgSWJ0TiegwvCHlbwcBDoZxXWH/pbLRr4s0giydIrYgmFxhfnnY\r\ndb2RwU0OXqFLvWlt3mlHp2zC8HOVwpfR+EqrKclv7hbI5U+dlTqlNX6VO1e4\r\niv/K2/ICYTb6JOGsMwm3W9qZP5ckazoM9Ptejs+D7TVmLeb0Y/8iAnuBjifb\r\narby9N455Qbw6yw8KY6DHHlRYKHx8U/PlBIiMlqVFx4Ou9h5SuaQEGF3QCwP\r\nit/bokIcy4MFqAJJU5v14NS1fZG0aN8fN9CBKh2Aw30GTsrKb2/k4p7bb4Tb\r\nuCPLB0sjrGs2hEU7ZiFzgzsjnQ9hwzue7MBNcgOoFrBwwDCC6+hYnY75Qsmp\r\nDpUTVfmazfJb4cPTzUcCATDwKc32+/KF1r4=\r\n=b/p5\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1664852417.0_1664852458233_0.3441481354246607"},"_hasShrinkwrap":false},"0.7.6-next-1665816659.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1665816659.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1665816659.0","@vuedx/shared":"0.7.5-next-1665816659.0","@vuedx/template-ast-types":"0.7.4-next-1665816659.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1665816659.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1665816659.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1665816659.0","_integrity":"sha512-vki7wmz/yhzvKkv7yZTTSnVKrpGxJakkwysrxWrSTYIPVHKbl6oFgZq9fzp7nUzCvZqz5+QO/thQgCv8n23eEQ==","_resolved":"/tmp/b936707db54c288d2e72d3a8a1aa56a7/vuedx-typescript-plugin-vue-0.7.6-next-1665816659.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1665816659.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-vki7wmz/yhzvKkv7yZTTSnVKrpGxJakkwysrxWrSTYIPVHKbl6oFgZq9fzp7nUzCvZqz5+QO/thQgCv8n23eEQ==","shasum":"699e4fe47a880531cac4101f8ac4b80c080b7f3e","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1665816659.0.tgz","fileCount":108,"unpackedSize":20260995,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHsrHHky1mpCMbbyH8PycjZadd2c38v5MTFvUpcuBSHFAiEA4T9C+SpYl08To/aXJqX5yUSaJ+ct2Isuutw4ru+lg/s="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjSlh1ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrWbQ//ReWLCl6DinTpMOFIrwWAcCOKQBLcSQPtL28LOpJs7hgKEF24\r\n/jlrfxkvYoH6ETJXPp2Msb7sEJwrTqj/IwDVM4yHTzFl/dJb5cRt/JTU8O6e\r\nv77w+TMSeNdWietA/8BiD5UZQ2eSgiacxgUE44rx+j9mSx2VFBGCdRzCOem3\r\nfmwdJ/HLohOITgqPIHHkw8aPvbHoNMqh4L5pBgU8TNXBjHrkH9Pqa9VO8qLq\r\nw9aOx71sR7eNrBBbFWSvRfBNAMnii5RS6IjIplU2TmQZMVYj9NLzXsaA9/t3\r\nQnHeWNT1zjdHbqPiJFPlX/Vxqnvuc2wUT/DRhWNXfBTXJWG0tgz17yJQphU1\r\n5M75dVgC+wsmKZ0bwgh5AMr+7zAgPPGsGkJi0qUPkMVL5zQHGpKMwcH2Vw51\r\nsGxoBx3tMH2zaF5in21fXxwK9aO8sjlRXQtS96ZdKQkVUSfkA4fvrQ6Az0KL\r\nsPdKAXn/YYvEzrgyh6db36XKYmmifo/nQFht18Z+aBltcJkeoDSOzXBiE7c2\r\nPP+fX50ofVNVhoKM3ftjMsvnCRD0np6ox7/c77+HaRpl2Ce6c+hBCPaTMop8\r\nU8LsXLnFtHlj1bhXQxurE0Wjaw70L8JPCnbVdOwAg87y5p1VqxiZL+QNm5hK\r\nK5WVGdi6Ut5P5qB8SXlVuU4Um3iEZg9h2UM=\r\n=jkVd\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1665816659.0_1665816692729_0.5112211520085406"},"_hasShrinkwrap":false},"0.7.6-next-1665904926.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1665904926.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1665904926.0","@vuedx/shared":"0.7.5-next-1665904926.0","@vuedx/template-ast-types":"0.7.4-next-1665904926.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1665904926.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1665904926.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1665904926.0","_integrity":"sha512-5kos8/yS7gbyjdYg9oBhcqXFBlozh3aIvrNlWq5YsvmSrb/juJxN25AVVU3gYhPxFy5+VwjXBO9Nqpjjv2bciA==","_resolved":"/tmp/0cb4fab51b83268ca436aa93e04f6dc8/vuedx-typescript-plugin-vue-0.7.6-next-1665904926.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1665904926.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-5kos8/yS7gbyjdYg9oBhcqXFBlozh3aIvrNlWq5YsvmSrb/juJxN25AVVU3gYhPxFy5+VwjXBO9Nqpjjv2bciA==","shasum":"e0eb5abb6c65e4cbdb6f05e3625eccf1d25acea4","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1665904926.0.tgz","fileCount":108,"unpackedSize":20503093,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDlMY5GTxnKT3g/5KI3isoY0iF7Ji5FvYCGVeQ6f/pvSwIhAKkmfomVgu7Skw3PLgWto3diLuRHIfO3ywjeOJ7Fkm+H"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjS7E+ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpbKBAAkjfc2zPhbamHsoTBFV1Ak8XPKt1mx5I9WsUHjyzvsfkmCFrm\r\ntH435l1zcOGF+9vPDnA5tmsp1Vjy7SYGfnY9GLUeDllK8Kj3ptJIJiN2GAY6\r\ndLttixGMouin8anDp6Z/3BNsIMZQhPCmUNfe6kMoivV7KQeLnNsVgsY9rEqW\r\nwhyWQuyr8qdCu13wdw4milCY8+liNDL9+uIR00VD7x2Vo4k4zFketsfwW+i/\r\nHrqWm+sLWKaETCTIbvedkwdi/yZAt1NyhLrLJSyL6Ar/VBpD5PAhnia4DHBg\r\nZfJ+f8TrJROz6hp0lUcIKQQGV5v7jNqNXIbHWifh1Ldu91mxRiAcX8CjtKdG\r\nFeInew8Vnm7Em3qs+Dke82tDkCc1dZ6xJJxqdZW4Iki5Y8LSweUddBPkzZsj\r\n0y/l0S6j7Wrm/Fhp95V5iyfhV7yR02vGSBdVCHPlcRTEzL3+sDo1/AProkNW\r\ntikPg/8g1sLRExLyK9Mn4IYAGH6cBEwbyybweg57Fd/Q5I/lMQlJTzGo8Anz\r\nz2A5Kkm2SPoilXELuEhF+/PhdcDosb7FQTb9Rp69xiZuD2P5cHgIRMuUwBO4\r\n9FSxW9O7knBIFRaRqZiEHNDp3pS7jZu6eV/bX7+9TuciRx6LccSLvZJsyt9I\r\n6Yu2PAoNdYNaz1MJtizVNruKlkx+hS2TSho=\r\n=z7kQ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1665904926.0_1665904957940_0.7541359025798327"},"_hasShrinkwrap":false},"0.7.6-next-1665979403.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1665979403.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1665979403.0","@vuedx/shared":"0.7.5-next-1665979403.0","@vuedx/template-ast-types":"0.7.4-next-1665979403.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1665979403.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1665979403.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1665979403.0","_integrity":"sha512-OvsxN+ioQwu4QMS7S+wLmak2PJBP0+aZd5Chum4kemBsNrUXM244KJ7pgAZ2AASBcayBQN2mwZO4ljQxzAs1JQ==","_resolved":"/tmp/25137aefb4bc451c08c3340ee80504e7/vuedx-typescript-plugin-vue-0.7.6-next-1665979403.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1665979403.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-OvsxN+ioQwu4QMS7S+wLmak2PJBP0+aZd5Chum4kemBsNrUXM244KJ7pgAZ2AASBcayBQN2mwZO4ljQxzAs1JQ==","shasum":"b15db230e828ef8b912b16a56662db19a592721b","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1665979403.0.tgz","fileCount":108,"unpackedSize":20510512,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCcUx54b8AFY1Cg4a1XrSryCSVv2aENPVc+8SeKdJR7KAIhAObOecMFmpHv+BVt0fQrWnT9ANQdoFOGq1bTCWwj1O0N"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjTNQwACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoTag//fIaTVE+upT8hrEadgg6gZQybFZYwjnApJm5oaFyOUWyk0I72\r\nPlxTvj9/bzHzymUDGMLjD3tZ322+hDPOJkrJSddigXSlPThQyrUIiI1MSTgc\r\nixth8HoNTmJpjZPkq8DruYxw63qaPJsk2j3bETxhRGeQ8ht26wzqAOcPWV3L\r\nBxzr85uLTdkPPtz2SfMzlzjwwEFZP1lvajuqTyR4uR313vhKNdTfYZ5IFGnd\r\nUyix44HU3WszwHyKvkkjRDNQDNvDAWyRpfwOfgUCxnuByRQtL2s7GAvvI2Cd\r\nA4gxyLFGxGgJquOqILy76EuVrUTgMimxYd++qacwZqNSVWloxuG+BBbmdT2x\r\nkmvs776rL6kZkElzY5qvjRLlVNCT9nQgpZ215uLQHdDzdtP/BKaD3RD34A2/\r\nnEoFXjbR9/oO+NztWIXB5XURUsBNKaSJFAzeiapRz+NN/0+/j9SfY3mdTTMD\r\nFFTnBoHGFJZY0irVVZ5Ieuwqdu6UluNhoFA9lBoH4C5l3eZtijwLF/RQlalp\r\nK2ZPJlFlci/euhq951PazV1OBD0EJJffezxtCvvW8PzoK5IE3HPh2NK+2gCv\r\nU6/BgH5mhSnLsg3EHp3V/JN86oXW63sg1uYqfVsMnwvv/BkTNIS0c2kHuQ+k\r\nk65nxUZEv1u1DPIf+N3cEJSJ7Dkg6mIb3Pc=\r\n=/OzS\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1665979403.0_1665979440055_0.5473474474199003"},"_hasShrinkwrap":false},"0.7.6-next-1665995999.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1665995999.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1665995999.0","@vuedx/shared":"0.7.5-next-1665995999.0","@vuedx/template-ast-types":"0.7.4-next-1665995999.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1665995999.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1665995999.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1665995999.0","_integrity":"sha512-7/eIz3ZZRcnEAEd/jwgD0ylonPfYwN3twvvHiZVX5Sgu2+TmRQq2Tgl6JdkBI8Kon1GkxB5LODOXgoxQDqPasA==","_resolved":"/tmp/79cb8ff28e88e15a49447cb87f59be39/vuedx-typescript-plugin-vue-0.7.6-next-1665995999.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1665995999.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-7/eIz3ZZRcnEAEd/jwgD0ylonPfYwN3twvvHiZVX5Sgu2+TmRQq2Tgl6JdkBI8Kon1GkxB5LODOXgoxQDqPasA==","shasum":"1b0547fa72fd8ada989341c99907ce00edb96bc3","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1665995999.0.tgz","fileCount":108,"unpackedSize":20510512,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAPSP5wCXV9hpUonEmmdUKd8DfaT6gyPzjChY5HmuPYxAiEAzgth91u9NrTMUVfUPx36uDtPqoqSGVQ37Z5DFbFAwUk="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjTRT/ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpv0g/9GZMFdv7C/fZWHBocaKyoBzpIh8zTBXAZs+Uhm7km/n6tJaEl\r\n49ffSqguIz2SOfut6C97qzLZgWXq8jMfVpb77rC45IzuEdYWUiwGSEu/ixrw\r\n/fsGtpVUixAQGAIHHFvZucq7kq2l3JS17n401wV3kV+xnQ/Z/kCwlJJUnC1a\r\nDDRX8mpkD1MOxlv9Ax8ZPJrxl2jSMYPiCMkfUjPH1gdPQc6AFzuc1m11XcOk\r\nhh9r4axSpApLN36UTfhXUJn8V96uSIlxq2si90UNiTBpUfh78bM1Us9HUeC3\r\n40Rc5faOYiHzTjbxis3X8VDgFE4AMzmo4/ObzNsU+Dzhrk5Vv2ILQo/n6cKW\r\nahpFOzjpogpQBEVkixTTeEywUDOEY49XNg9ypDcMLl31kAjq0RZnMFKBmNem\r\nn0Ka2tNWzj/SODv9m0raCOUSrGKaIXOylFmIJmx91yCCGi0srPHR8hpbP2eC\r\nrNaE2l7klu+Z4FDkcjnr6UhHOZoq4Xi43QRCeRUUicQyGkRRwuvEWLE5ne1z\r\nwud8rt1g7YnIJ/awbMdz3wRqCACy1r8TMBwaBaazHPTTU73fp+ERpLRO2Ugk\r\nbvj9wEb2tmfFQ0odOcgrxJbViBIKlk+3dOG85YjHI0888uCYIIWLTOVM7I1K\r\nG39sz4csLZ3HW4xjMcap81H4prcfHYKSVOk=\r\n=WVgK\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1665995999.0_1665996030814_0.8753723631161403"},"_hasShrinkwrap":false},"0.7.6-next-1666119500.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1666119500.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1666119500.0","@vuedx/shared":"0.7.5-next-1666119500.0","@vuedx/template-ast-types":"0.7.4-next-1666119500.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1666119500.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1666119500.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1666119500.0","_integrity":"sha512-uGVIaxULdh6h0GsSkBblvppBPYPSwk01d02YcVp9RS+ldnv9duACb1QElyOpf73/mUbHFwRJk7SeyXj+QYzM1g==","_resolved":"/tmp/74dd7bda98fbc97bac01d60ec9e4b53e/vuedx-typescript-plugin-vue-0.7.6-next-1666119500.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1666119500.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-uGVIaxULdh6h0GsSkBblvppBPYPSwk01d02YcVp9RS+ldnv9duACb1QElyOpf73/mUbHFwRJk7SeyXj+QYzM1g==","shasum":"651f78e612dba272af86794a348f92fef04495fb","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1666119500.0.tgz","fileCount":108,"unpackedSize":20519577,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA7G++UaeGf8BV2H17HhkYD/mMZtyWveuDZHXrJRLOy3AiA2g0mcnnmAWq9CZulzH+Cx/HEJXUkQm37P5dCyBg6rJg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjTvd1ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq+9Q/+L6xlOE4TC488AX4iYWSPCY2ScXYBGXJMXJHI8kBvVbEtybOY\r\nlum6Na07bz6sOC7y/b1Q/lHkoNegC9LtccKQPz4XjcdKumqJKVXR4pDJ/wYg\r\nDXkrj178em4mGNYpZBz0uqO7eJSZopR8COnlrTDUxfpW8+HoOJgWAvgUgJhf\r\nthPy1vZMU17u3FwVzIie3DnlCFrgLfFkJlttdReaMM+nNUuiVDJq/TqkITFU\r\nCNiuC+qlCKYlRSXovOPpjz7GY4yzw5PL9zjIkOE8hIG8CNsO7yZdPEEoJf0m\r\neQr1+VYYUXlV4qnV150g+pCJuBXNvhaOqeg7BfBpsmfnaRwpX5Hh5MLz/Nxm\r\nMyCKpl/pkYn29tk50EUAukzpMql0d/C7+5P8ozGmXHLC35ACflKAuB/ESKRR\r\n8Gyo+xYA6AuLBBqch2oSTTRyIe/GM7rLBFX171ZFWGyO9BKrFuyFjgdIC4z/\r\n3yGAmJ9/lhPvfVohef75Ip7xvca182xRVgEoEOqXxBVlub1QIiSrm50ZupnI\r\ndrhlgXN7bLxSqlExqwCWpTGXG2g3REfJH9B3lM4riagKvQdzVokncoaLgaLu\r\nJPTrOK5dkszkpanLa5+5DvuZ9YJoH9vcSuxnAXODDRTvn7CfU7WDJ6M96x2m\r\ncbpvTDZEyTALlElD+ix5/nnlyQxMehe1B+k=\r\n=36Ot\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1666119500.0_1666119541253_0.07622695617498154"},"_hasShrinkwrap":false},"0.7.6-next-1666207395.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1666207395.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1666207395.0","@vuedx/shared":"0.7.5-next-1666207395.0","@vuedx/template-ast-types":"0.7.4-next-1666207395.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1666207395.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1666207395.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1666207395.0","_integrity":"sha512-Arikb05WEZAIqFTzhsIa2L6vVHU0yEd6dZHl2MAAoWGFAEO1fLmryTIn2eFE5czjPMMISygYiYqSXOhn7vNJhA==","_resolved":"/tmp/d997aa716794a50b4bf13c5183ba9982/vuedx-typescript-plugin-vue-0.7.6-next-1666207395.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1666207395.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-Arikb05WEZAIqFTzhsIa2L6vVHU0yEd6dZHl2MAAoWGFAEO1fLmryTIn2eFE5czjPMMISygYiYqSXOhn7vNJhA==","shasum":"fc2843c8a6e23a055815fa9217b4611564282423","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1666207395.0.tgz","fileCount":114,"unpackedSize":20566587,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBMGgTxXB1i+E1z+NVpQZBz1+Zb4pcSYYWNQ2+mo5cEEAiEA79LMqpSOjtKArGgvrofSgQu1oO9jfPd/abVsX69wa9A="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjUE7EACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpO/A/+IJuDy+fqwMfLP1kc1dP1xLRSPNoUjGeSvvywY/f/VT54kXii\r\nrmcdg5EFzs0MDkbn7sWniAFYSEvDcjiogWEIc1sKkfvHAorScg1bIQ/lY4Po\r\nEhr1xYewaTtxK4Cl7AB74ENT1VxJsScXExaFKcZpSsi+Oms6zIK6Cx4PZk7Y\r\nApTlhWWEzgQhjIWQuxlnv5m7NxRgnWyawyFktf36cTa+5vYHArehAODEE6p2\r\n1opEM33lQObdEDjEc1egvMR0OqJlbkuKJT6EgP26V89jrq+bC/sEv4fao8To\r\nBzAzWQNkAsak6yrbtuEe8Tm23EIOcNy5X1wGM/Sdr9JQYKg+EFjrbMhHU1pZ\r\nd2K845WVGLrhlYlAxqByvN2HwKR5AygNC4aRLjY8a0RI2Nf6DpIsThITAG9X\r\nhzgSrbY4edTrPaU4NeSBv9MRco336//Tp35pbEQb4KLVw+A2F142Bm9QAZnc\r\nCa5gufkVu3WFrcMG1O0wu7/uQ9ASHB6WVxrJTJR6AuqeGqD8Mhv6ivA6Myt7\r\nR3CUfhKqCMTV8gdHgxWNfPT7sdRRndsdXUFeCeVUHGwiwKFloG2/ktjW59Q8\r\njQadFA8dImlwlR5mHJ9ULPpess9fYyvkg5LZqY7nQpqNLu1TzvEn9Gq6OAWb\r\nowPnJBbCSDFQihkjjlCfDdxxTD4K13Fr4HA=\r\n=WggB\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1666207395.0_1666207428012_0.7304699763666822"},"_hasShrinkwrap":false},"0.7.6-next-1666251997.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1666251997.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1666251997.0","@vuedx/shared":"0.7.5-next-1666251997.0","@vuedx/template-ast-types":"0.7.4-next-1666251997.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1666251997.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1666251997.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1666251997.0","_integrity":"sha512-zh0TMQijyipc69VMKReVqgwyLV5FbJQZZjDg99Qmlu3KekOOIIVOVru6VM6qWE6xkTUEP5pGp0zrMhfQaqlF3g==","_resolved":"/tmp/46fc43aca0c40b9c23cc5b05ff556b01/vuedx-typescript-plugin-vue-0.7.6-next-1666251997.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1666251997.0.tgz","_nodeVersion":"18.10.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-zh0TMQijyipc69VMKReVqgwyLV5FbJQZZjDg99Qmlu3KekOOIIVOVru6VM6qWE6xkTUEP5pGp0zrMhfQaqlF3g==","shasum":"24dcd2c6c0cac83ffd8047f3bfea3e3752727c00","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1666251997.0.tgz","fileCount":114,"unpackedSize":20566587,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG4BT6DaxafffOTO18gF3zai+AgpMG3q3s3+nCJybMTZAiA1xvWgp5QmZ86+NUrLJDxHHuSAqJbtZ8jJFwn0Vdm5Hg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjUPz8ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmolpxAAipEMG31AnwP0WQ7AIfoypKYdpIuOQH1ryNemrjAU69Xweu1S\r\nhOwkjVFE2shZ2VodprUvm4Kaxpp/MV85w2UE4nGc8aryQJDfEIJGV48RryWe\r\nKtGWuw5j1gl/9cO8fv/tC3YR4ucO62uCy05lNT+N45L+CnDRDgetnZe56HA2\r\nr15TOsUOx0LGCBorE5ZtqyP5NHzihFGYwafpMTFLcnug8Veqj1ew/edl22jH\r\ncmrHC62niyDDzICS/RBBVRf3pHSM8IqUdT11I/BEhaat1zLMoes81gark3rm\r\nT4ClJaOrVuE4c3Sf+Dm7DAfi3QQiwQbZqm/4OlfLJYzD7zIKmZQxhZcFCO4r\r\nxMyQwDCJXqj8FedVzKRnqWTWuC1OJLG+VI35HCrZzK3ZyoNZvAsCPZ8poxvs\r\nlXjrCsodZOTwWzUI+HuDxgXdcg4SVjaRPMDIKzCmacGtolKfQ6qVtO2WqDCZ\r\nt4Y6WPpkcwW4AZqtHHZDGJt4PeW0uGTrvk/3WabAXrUXhg+hZeXxD+7iugRq\r\nAMehDqEkx6+x8JKm2PHYkxyp0EceL1NJoXSKib4mADInkgOh6qkuFQ3uk1MT\r\n+eprp7/hYeUH+coJSya3mTqLZa8jJe3b6aB1g8o40uSXTZEELrzJGilYYVBh\r\nhd+dGa7vJOvpsvpyiERYwVlOLYUY0b3OoDY=\r\n=z7Yw\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1666251997.0_1666252028630_0.9543803966761368"},"_hasShrinkwrap":false},"0.7.6-next-1667343140.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1667343140.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1667343140.0","@vuedx/shared":"0.7.5-next-1667343140.0","@vuedx/template-ast-types":"0.7.4-next-1667343140.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1667343140.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1667343140.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1667343140.0","_integrity":"sha512-qQMxpPXS+i497I/chxUEO56ZJmE1+xUx4S1fdeROPXuwpO1UFG2bfPIgCKhJTc/LacAoACt9KStz0brp+0m/bw==","_resolved":"/tmp/2e547f9236d8cb76776a3b35a43e0918/vuedx-typescript-plugin-vue-0.7.6-next-1667343140.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1667343140.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-qQMxpPXS+i497I/chxUEO56ZJmE1+xUx4S1fdeROPXuwpO1UFG2bfPIgCKhJTc/LacAoACt9KStz0brp+0m/bw==","shasum":"c1a7c8ac472158848f89ebed63be745552f9d16c","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1667343140.0.tgz","fileCount":112,"unpackedSize":20549295,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDUnChQyyuaAPQ4CQj3VsrS35IZ3rwuNB9aT3Y4U5BucAIgKqGFJmRtm0jIhMUfvBdHUOU7ExrPDFvmb92ABepDIis="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjYaNBACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqqeQ/7BiR5SUjoPoU7qd5OP7p5NCeS7rJEk5bMVKvcuO3TmkvmeV/T\r\nO0ZqO1/fXa1YxIWLGrYCGbKtzPL3U3QKraFuz8RNJO8MgpHcbUDH8im/jIkT\r\n7yjUDdVkusFbfeHRaNdTZ5IzZNQD5kpOXenYLemVOdtBxSzyjamU8/OBkiAZ\r\nGNFDwQc7rq08w1K78Our3CxhO3dnNUugKoR4Q1JdkaZWOEg+gbuhCwACwoOM\r\npGepy0pyVm1o6QKImG2l23pB6oBh0U0IWBGUm4JaIqipdjLxtVJQj7eo5V9H\r\ntJQ7cubc67kPA/ms/43w/DEJx4GM0P/fv5GZp5ZcfV8803lQuSZPWSnkWwRS\r\npqPk/gUFcjme+b7TRau57pDtLWFpshqjAmoj2JK8YHofPR0DHQByaru41nYv\r\n1OGXRxVas+HnVKIqFJ6HrdAVwm5r/ey6E4fqFeZDxoEfNvtmK3wOI8jHbplW\r\n5+EmEjlTlm7bIds3Lhb5eCnfdCnqcXUn4uVA5XliiG6/GQJWnkNwuQV9X+qD\r\nIDOMUPUJJ4UrH8B5wAukjzTR0cVowDI74fMFOL80kRhdObDMHmVW8xXWSxwW\r\nk95ov3kLqRsr5Cgoln7AMPXqk4dVCzVFfEvrqBN3kHAuGdHSr25bSQH4MrhR\r\n5L8a9inAvB0ACsXAfHA3xSFgO0B17qSdM28=\r\n=D/5I\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1667343140.0_1667343169308_0.8690368045345676"},"_hasShrinkwrap":false},"0.7.6-next-1667343481.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1667343481.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1667343481.0","@vuedx/shared":"0.7.5-next-1667343481.0","@vuedx/template-ast-types":"0.7.4-next-1667343481.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1667343481.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1667343481.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1667343481.0","_integrity":"sha512-A/ZTlKtrj/802YRxH7tDuu3Tb8MP0x/UYQasHB5FY/sR6m/rErXZ1bbKJrYlvapsGk+/nT20mU5jrP6ccTy0Zg==","_resolved":"/tmp/2ace529de67291cc4548477788282c44/vuedx-typescript-plugin-vue-0.7.6-next-1667343481.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1667343481.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-A/ZTlKtrj/802YRxH7tDuu3Tb8MP0x/UYQasHB5FY/sR6m/rErXZ1bbKJrYlvapsGk+/nT20mU5jrP6ccTy0Zg==","shasum":"bc48f6630d457f0e3beddeef795dfa8c0954447e","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1667343481.0.tgz","fileCount":112,"unpackedSize":20549295,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHcAaVsbiRoJAB05Gx/lwSQlc3obAy5pk73oNW997DKOAiEA8bMGWyed6UNRQkltkG/rU+tG7TIpD32oZImesUB76JY="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjYaSeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpqbA/8DCynqtAMyUl74kuqgHvtpEFuprNDX2TseTQA7mhVCIP4hY8s\r\ndu2bw3DzUsa1rhTozBqYksP/MHsy6/tp7If76eydg9FI8HNLXrnKQVFdj05w\r\nZWHC4HUXW5JS8gUwt6omzOAXJOAJTX+FLIB0QkHIm/UPHXjaAUP253EZotl5\r\nGpujy/s8zR0boEX1qjpEyDo4EAN30TQ9LZKEAP07r6df8NymahvWK/kF3rfl\r\nsFcqqUKLLW9JmJdSOH6cMH5Tqo8L/MZ9ZhJT7uXm3gk7wfCp6pstwxnPeYBQ\r\n6rf3e5nArvbFtP5Z4jDSA1+jQCoZQc92Xi+fE69KIYQxE3lpDYa8b3b9H/7j\r\nUi+ilZKy6td/LQZsijdbf8/Mgthh6yL0gMxKhwhB9hqTYN7dfJ6YPrq1Hp+O\r\nL1iNBLFPEtNiqqGo9PPRCbactSkKq2La5R37GLBAQE5EPKcqbL3aLpxxm3iA\r\n/x697em/qOtUTyHeVht6FJ0qDcB6L/GUp5oFE5VmyyYh90aeOHpmyz4Aiare\r\ntyPiqu+oDS2r1slKjuoKhnNsgYGqvs+10hjPmh8aRnM/Wgb5NW6CCfcRGkEf\r\nNIP1b3hASgKGJZ7J0tw4Tsd31WG1AdY4iuURXd0unb4xDadrPnJLEGJj+rmu\r\n0f9+laHRo6rEMLrMOEBBiBODDnZ+KIwgXfc=\r\n=sjsQ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1667343481.0_1667343518399_0.006673054659255051"},"_hasShrinkwrap":false},"0.7.6-next-1667345249.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6-next-1667345249.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3-next-1667345249.0","@vuedx/shared":"0.7.5-next-1667345249.0","@vuedx/template-ast-types":"0.7.4-next-1667345249.0","@vuedx/vue-virtual-textdocument":"0.7.6-next-1667345249.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1-next-1667345249.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^3.2.39"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.6-next-1667345249.0","_integrity":"sha512-VIhXST8YBMsFtTOZS/74VEE8+qmLYp3ZfORLGShQJCElpFiRvzd7fz5vy9Gsad8r1U4LTX2/4UoLZKjwbgg5TQ==","_resolved":"/tmp/534b2d47ba7eb484ff35f0ab9b19309d/vuedx-typescript-plugin-vue-0.7.6-next-1667345249.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6-next-1667345249.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-VIhXST8YBMsFtTOZS/74VEE8+qmLYp3ZfORLGShQJCElpFiRvzd7fz5vy9Gsad8r1U4LTX2/4UoLZKjwbgg5TQ==","shasum":"57e413d44e5945a54162bb7586cdf6bac865d90b","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6-next-1667345249.0.tgz","fileCount":112,"unpackedSize":20549295,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDoq7gNJEkYOo4z14GhNFlKo8hUUp70aDK6mEnXIj0/nwIhALnY9/qYXQqee17n87KyuOWY2DVYP7B23K2nqj/4VMfZ"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjYauAACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmowVw/8Cjs5iKu9/d+t+XrZ4IaNAlubtQVVfGnVDAGZcCoX2FS2Wbxd\r\nD+h94v8GymbJDzDSGURUUcupMH5TxiONgt1WfHxRbFDgzRd+EJQkfM/kcqUw\r\nXx1XS1WSD+JyafkQbSoXLuCGg7dzad3gtDzssno5FfQ/8l1BoCLTBgUNH0Qb\r\n5JSZ+9O3sS9VfE70gDevmznJ3uQWx7bDeLwQ3az6vFzSzq2yv4Iea/L4uazZ\r\nRutiPpR/Xy4x+mO5GW94MbP5fiLC18fxREsJ0CLUi1LJuqMaDSJZLpt5QDv/\r\ntm9SedSLOwg4kT0QPTjfjFBeNKdRR8WnO/qM0TVrwS3xxgerYh0aKoNqZt5t\r\n4+amoL8+gX1pixrlMCY1oc1cPbyNzapCyH8B0bKeZBTwc2FBZvNMBOlbUgc3\r\nk+IEGYyH5Xd24855fGLHRafpivNcIEdYxsSDXVr8OrHcVN2/+CHHOjkXu8C3\r\nUA9zWtBQ5pDE7Ooa9MHaYj3eT7b1wLfBih4CMDsvgJtUhS2vSV/1jg3DNGDP\r\nX3pt1/VfxYha2Efk7+cV/NUsCKRgEq2ufrHHkaHAN8/4s81YTwnppfBRQIg2\r\n3QDM45mZJdEoV7rXVIGemnGdcexhV+tk7LyOD9lV906oR+b0LMx8rhsBfAOb\r\nGzh/ktcFdEdqO5PYgo9BFJR3E7A89F3ncPM=\r\n=IXfd\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6-next-1667345249.0_1667345280134_0.7479745441759393"},"_hasShrinkwrap":false},"0.7.7-next-1667345594.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.7-next-1667345594.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.4-next-1667345594.0","@vuedx/shared":"0.7.6-next-1667345594.0","@vuedx/template-ast-types":"0.7.5-next-1667345594.0","@vuedx/vue-virtual-textdocument":"0.7.7-next-1667345594.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.2-next-1667345594.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^0.12.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.7-next-1667345594.0","_integrity":"sha512-pi2GOQcraDy4Qm/2aaNhiKhBBtAz4iKzF5iKLRG9YZRpdvU83GFyiQ46rv39fHu6Uw8XxZEntYXRMDEzoWr4fw==","_resolved":"/tmp/21373903bd02f70a01886490c14eda30/vuedx-typescript-plugin-vue-0.7.7-next-1667345594.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.7-next-1667345594.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-pi2GOQcraDy4Qm/2aaNhiKhBBtAz4iKzF5iKLRG9YZRpdvU83GFyiQ46rv39fHu6Uw8XxZEntYXRMDEzoWr4fw==","shasum":"da5901f027ae53459711bc1b02108d65c95f1bcb","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.7-next-1667345594.0.tgz","fileCount":112,"unpackedSize":20549295,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCsm8gxaNVBkk7pp4uWHv0tNjcB1b9WIEEhvshR1+2gfQIhAPSrC2ZQxDDsSjqr9U5J2i/J9ftxEoqUnHWo0LR3lcaj"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjYazbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoC9g/+Ilyz1YVhelbEXX0kygU4fsP9J9KvrCdKLL+8fcpeuW8yXehT\r\ng6v0F4NgFfM3z7Clssg1oI3nMgUUsO4u/SgmW1Lz4LlQH9VW/FDsRWwGXmWO\r\nErNO05sIogVe+V4CzjM8utO1dvVZsL5BxDOjV28un+t+7ESlodi2EF3hTG73\r\naoxBXfQAwSxPqmmp8qXq33eAT3oMacJHN1B7WtY/Nlw+/Fv3O5R3PPyWI/iC\r\naQhai2GyqYyzw1wXSobczLWvMUUHmV3XFR7O39fs1oqTR6oJ5uaU48OWhFhQ\r\n1BIHAfRjNG+y7Dm16ycSuZHAYtyPSCii50Fk08Z5ugeJXBnqvod81cGL3ymC\r\np2E7oUA73N6Ie0AKyB5WM/PhpVPZwEYml/PpH4t4BojpDxEzto4SA+LfNTFy\r\ntVpNR5CFJa/ewJIDDvAk2katerAihG2vsJVFQd6OwFiPFeiKEwW8pRYNifJm\r\nYUMTBIrE60AqdESzAWu7aKY2vxVOedPqK5IenkvFX5MI6fnR2sApqgXW0XjC\r\njueuPSp1twIi+wEmwuYuCkvMhrkeEBMX9codxsmRJyg9jPckhjmdTeT1ipok\r\n+JtBBX1ASeRUnmY9B3tdTrcMqPF7TZ8HLgfW/xnAwwwVEhoVnOMAQojobBR3\r\neuGauvp4UL57hB8aALU1rUvOmlQhjcbHA2M=\r\n=jzrI\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.7-next-1667345594.0_1667345627488_0.9075283454784817"},"_hasShrinkwrap":false},"0.7.6":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.6","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.3","@vuedx/shared":"0.7.5","@vuedx/template-ast-types":"0.7.4","@vuedx/vue-virtual-textdocument":"0.7.6","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.1","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^0.12.2"},"_id":"@vuedx/typescript-plugin-vue@0.7.6","_integrity":"sha512-8kaobkgrxEa5ebA6CptUBQn/gqBszBYlbmN0lPM2MFVpON7mF8ovqp/8Lzgg+7im6LbQ/EeHN+XrJP2y7BuseA==","_resolved":"/tmp/72bc41e01b5c78346adf8149e3d4ca65/vuedx-typescript-plugin-vue-0.7.6.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.6.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-8kaobkgrxEa5ebA6CptUBQn/gqBszBYlbmN0lPM2MFVpON7mF8ovqp/8Lzgg+7im6LbQ/EeHN+XrJP2y7BuseA==","shasum":"19e8c209bc7533e7401ad57db31605492113d64c","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.6.tgz","fileCount":112,"unpackedSize":20549187,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCKLq2axqrPOK3DElG2BJs7iXLLxBj8StUsaPrXtcB0zQIhANv2fxVz4ti8vRcXom5zLabVnZK+CuUGrf7HsMkAGAvE"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjYazlACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo5zQ//RHQGt/841mLIOMvW3RvEpnAJx+uOMuWplN+VcUAjxK3qNffG\r\nE7gzdvcAifupRH9vb8BekFQekXr8X9yloy+1UlLDqi4/xDzQW4r6BOtv47Da\r\nPY/MG/eFBBP5WH7UyCLNFedzeznsovzo161/t0Aigs6HFBR6YswJqGDCt3+d\r\nxPHHZXkeLm5MmRcDMxv8vx5TvCDhIkix2P82X78pntHC3mxK8LK9guvXjjKn\r\nHIZx2ylLCgW3aVeczoYocjOSQ1CJz042/kzTxR/FODALlpW0d+trBSkQdnmH\r\nLLy+O4hPMQPn4wbBM6ibXWjQoAl2j2HaH5+WhleKiNK0/NeZ1AyNPoP6h0pc\r\noVG8xxef1zbFF/Ik56ftmPjThFZUc8GRP9YEFNuNdIzZ9mU5TFeL1JhHRzJn\r\n194GyrF1B1s6JTNIfx4ibVNjXWz9boIsFsY5iL3/TOv/h6t5PbyN9xYej5Xs\r\npc1T4eS6e0s73GGxwrJC/TacFAMpQZ1weCGvTrXkK7j/tz6PsK9778D/04/J\r\nhNTjCnWLZk+FCgSU5AoJWbBKbGqPEPScPXgvIhamSc3jLpXWoFAhyJJV3deG\r\nyOyz5W0cSM6TiiyY2g5yQzx1QfwTCL08YwD35YvFUCQ6FYm5UzzS0CFFJVRh\r\nUWeQ7L6GklZpJqQFoqyNzq0MeYG004Qjztg=\r\n=4lvF\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.6_1667345636852_0.21817797384747717"},"_hasShrinkwrap":false},"0.7.7-next-1667540051.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.7-next-1667540051.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.4-next-1667540051.0","@vuedx/shared":"0.7.6-next-1667540051.0","@vuedx/template-ast-types":"0.7.5-next-1667540051.0","@vuedx/vue-virtual-textdocument":"0.7.7-next-1667540051.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.2-next-1667540051.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^0.12.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.7-next-1667540051.0","_integrity":"sha512-hzRKTKoSPeSZWKhinHk7SD2MhiuqyejvUbOsBGZfBhSbgjndeuGO1TKvGma065vcs0CU/86g+ZxTxP7TMxK2kQ==","_resolved":"/tmp/6f9342f9dbbbe2f953f0270f23a9bf5e/vuedx-typescript-plugin-vue-0.7.7-next-1667540051.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.7-next-1667540051.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-hzRKTKoSPeSZWKhinHk7SD2MhiuqyejvUbOsBGZfBhSbgjndeuGO1TKvGma065vcs0CU/86g+ZxTxP7TMxK2kQ==","shasum":"0afca501dafa0cfadde58048456816266cdf5df4","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.7-next-1667540051.0.tgz","fileCount":112,"unpackedSize":20549185,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID41KcsIY2vrLiedDyOR0TjynUGCp6xS4do46jCfCPYRAiEA8o5uVhAfJEF/hbPl2Ce9PhrDOmGHE+0tJvBRO3UCuTY="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjZKR2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrDNg//cmrd+nNUQkxlyfC5Ji0jnGnd2dfrqmCV0pwCMZqU1iu1QiFh\r\nphGj2BIsIzTzOypn6v0QCVZQ2YsnsUgPPJ0fTI4dgtWZZtWRRQoJnOgubhwz\r\n8Rh3P47xGggQJPyS37+hO5Msj1H1pBSzlOg7CHnZ1Mpr3Lkji0zLz/ijNzPD\r\nwX9ERmQ9xPqjDDQ5epRWP64hsksBWVeQKMsDXYmXGISO92CkgId9JwmKNTwW\r\nTb8ugoyEgvEVC6rD4xSYjqIZl/DFSTSDi8Ak08kxRI2H/J82t65e3iAttP0C\r\nkVh6UYi/32jDt20Dih1WQ9tKnLcYR0LUa69oQomF2rk0kRHOHtLUEGHeM4HD\r\n9P9ha0fuGSswWhKgmDkpMsJpFwQcNJF9DVQoyk9FXP4g4b/iTp41lWEK6DXE\r\nlvJ44Mh87SHgAMUuxRkCLUE1MPQTTCaUn+ZBXlzNaGPMiWqHnVdgTiQNdo7A\r\nngppiX5c55hvwDne2+tHVqKJojrSnf+RrBsrHMzueFAQXAv0rtiwnwhbOpCb\r\nQGU1dg8j/ilaPAOYykFAabC12q4DXGvI8YvcNpLPb6tX7FPM97w8+Ce0/n42\r\ncRJwKF3evM20+/lW4EJol43Mdxwno/ac1TYogdXyUfHBCJnNIM5znODx5X8w\r\nczsasJ0gMfN9jnp5McN3Vi4CiIMKbG1G4/g=\r\n=CyC+\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.7-next-1667540051.0_1667540085682_0.9525123169137366"},"_hasShrinkwrap":false},"0.7.7-next-1667576550.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.7-next-1667576550.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.4-next-1667576550.0","@vuedx/shared":"0.7.6-next-1667576550.0","@vuedx/template-ast-types":"0.7.5-next-1667576550.0","@vuedx/vue-virtual-textdocument":"0.7.7-next-1667576550.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.2-next-1667576550.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^0.12.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.7-next-1667576550.0","_integrity":"sha512-t8XgIRlh9L9uJiYRuofYy3aHrBNui7U9HaQ/u/cBMFSamepeZokWRpBISFn+Z/3qE+43odsQBjyS0pIqytNO9A==","_resolved":"/tmp/13da4217665dcde693043a9312ed7cb1/vuedx-typescript-plugin-vue-0.7.7-next-1667576550.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.7-next-1667576550.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-t8XgIRlh9L9uJiYRuofYy3aHrBNui7U9HaQ/u/cBMFSamepeZokWRpBISFn+Z/3qE+43odsQBjyS0pIqytNO9A==","shasum":"e21b496571c1f77c3fa1eff7edae8b6166f31e99","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.7-next-1667576550.0.tgz","fileCount":112,"unpackedSize":20552448,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAFyQ7+k8kqSqJBH2GrdarL5CL3muLVvMuNEkApcFfXUAiBHGZGPBSuaRYOlgVZwN/duGGa9v6uTi5m6WvaGcD/t9g=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjZTMOACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmquvA//QE2M1GVRVmq+Y/NNeeSdsxMl0kEJ/Ynz7o/udGlCP3o760ZL\r\neCS0HhkZTyFTU8QFvVOKcwR11b5WLItef1T6c/Fzt0cojbIj4JLTc0KzcsrX\r\n94ca7pmZrGQrIh6w6xLZSfDT4Is5yf5K6TBYIkzPdQ4lCGHrvjPb0CPRJL89\r\nRXs0FXXcgEoLBRB/Z1XUwaDmuNOgfYKse+Yta9tM90bR9HDH+KycIFIxa4El\r\ntrTEXr97nCBCxvzWlkRqWiuA/pj7pw1Ykjt8DzNvRQMVli4N/GArUcfmVjwo\r\nQxOhlRX6CLvTIp47UWZQIIfe9rgypEV4TcvkJTiFIL3a6lqXnthBRkgfRmxS\r\nF7HRYdjO6kJAIvw397OMoYZ9k4t7y/LY3Fpim0//DPHvW0mE9HagPUJahUBA\r\n8Dkk/zI88QLvFf+MIWJoLMRiPOHJ0/QLgL8FGGmDTguIULKMsOvKLQR2LCoM\r\nbWEwVP5svMPJnC5m4fRu01TNFkHiR4NZCUsHAZZXJVmMmQELW+3Y8Xldbz9g\r\naauddpTXtzR6ByiXcvt7AkSUOcNjcdmaJNtLPloKBDCi28x/zs453ygqIBwB\r\ntHQN6e0Us4rKw7nRZb3X8YYnTHEtL89s5N9Bs2hOo4P+DoO34DHW0y+mLAjD\r\nMeXh+bl6lcpTF87jWEDtB7M6BVWu/LXBqSU=\r\n=M38e\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.7-next-1667576550.0_1667576590444_0.24655802994390918"},"_hasShrinkwrap":false},"0.7.7-next-1667925330.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.7-next-1667925330.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.4-next-1667925330.0","@vuedx/shared":"0.7.6-next-1667925330.0","@vuedx/template-ast-types":"0.7.5-next-1667925330.0","@vuedx/vue-virtual-textdocument":"0.7.7-next-1667925330.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.2-next-1667925330.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^0.12.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.7-next-1667925330.0","_integrity":"sha512-doqpInv25NiLv39Lys/8eXspf4VWavqCJevmbNIYpCrAIfLGQ0MaOP3hANXq8mLd0b5WQ8G1NrM7vNf94yeOzA==","_resolved":"/tmp/b9b3ef165ea58c8bec39c63b55f92302/vuedx-typescript-plugin-vue-0.7.7-next-1667925330.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.7-next-1667925330.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-doqpInv25NiLv39Lys/8eXspf4VWavqCJevmbNIYpCrAIfLGQ0MaOP3hANXq8mLd0b5WQ8G1NrM7vNf94yeOzA==","shasum":"f313198d772912361f9fc74584f9d4dc2ff20193","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.7-next-1667925330.0.tgz","fileCount":112,"unpackedSize":20552960,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCKYWvntv8zWqXi+Fak5iGhuPQGwJRHsWmBK10zjUQpbgIgGKj4Lo3sqFnMwHfahXs6Xj/YnnejclNn1/DqlPCe9GI="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjaoV2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqCTg//Z0cCIPsDhihINVRvhfOK7rBsonyd2Aw7zb0wD3UWK2iSBU56\r\nwjjti5J6d1UYqAiVSKv3Tzgs6KNirYCU5HJ8cQwRMj6L5FngcjKDhKEUHSwk\r\n+KWfKldp7m67kJFTbdrRenwCscYrHdR/5uDMN19/3f7ESvPM4BYTMHd3Hegl\r\njPBUCE/mrMTTr1ShMdMNXjiU836f3dmRkic2g2UCbT4TwEEpQio31XPIjrAQ\r\nP7uw3JW7dk3JCZN4WrsJ4nObHmDQdhNEF9lPImHkn0yNR9G9R28/cT/+u4G1\r\nIS0p9yF4fv6lJsxfj+aqr+mxSoAlLJ+cGfowyKUmNddgcSCjneqo4Wv6LW0k\r\nsDolbRdDQZTO8lDlP7gUVm+dp5K58eetv1BhpeGZlZjoVAro4Q+zHFFPeCHL\r\nJuXsR63NIsNKD4xtCDq+rAKelCOfHT+Y3qX0LISzWevLUNol98bJF3t2453u\r\n2qpYSbndAigGV/rkndaVgnjE5vA/4lbt6iKlsSFI/LvIjBWF+wzMYIhaj0mL\r\nDiCV5zhWe1WHgYrT9IKRovMWpR6/jeH0TXrYtL7yyOfKXj8Qldtz80prmngK\r\nFL9Oxvfg7udQAP4Wawm1ramyPnYRp+XJrzGKM6XZ+c9cR4ga/2XBU3ALDPr3\r\ni+eEfZDLQNrp5ZG7glKiG//2ZUYkspb1IA8=\r\n=t0j8\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.7-next-1667925330.0_1667925366022_0.017597960462202078"},"_hasShrinkwrap":false},"0.7.7-next-1667938774.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.7-next-1667938774.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.4-next-1667938774.0","@vuedx/shared":"0.7.6-next-1667938774.0","@vuedx/template-ast-types":"0.7.5-next-1667938774.0","@vuedx/vue-virtual-textdocument":"0.7.7-next-1667938774.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.2-next-1667938774.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^0.12.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.7-next-1667938774.0","_integrity":"sha512-c211iJ2CFsHPG420YH/nTRpihner+f+tWDEp2m+QgDuRaJBqCLteSQuau11Zsl6jFTnm1Q7K2JGctACQvGUKXA==","_resolved":"/tmp/67f25a33e056c70f847d71b1de1d0fb3/vuedx-typescript-plugin-vue-0.7.7-next-1667938774.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.7-next-1667938774.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-c211iJ2CFsHPG420YH/nTRpihner+f+tWDEp2m+QgDuRaJBqCLteSQuau11Zsl6jFTnm1Q7K2JGctACQvGUKXA==","shasum":"30218a97fda447d82d06948952848b9e1b09a426","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.7-next-1667938774.0.tgz","fileCount":112,"unpackedSize":12188165,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID9WwGkTXRwElxVO9CyP1vLHUS1kdD/OuZO0QmZPT27EAiEA1gR7SCE5TZ/b1acAbPFMPkpcSOVAcFkZ2yfC7MIpW2o="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjarn6ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqeOw/+Psz9OerGObc+ANUCs+UDesKR+QWQawF91s9m7xaUADv9ZuU5\r\nr+AdnFUEE1AmkzQF22a58q21+EqychW6K+kvwGXV9YfVIvAObwuGDzIMBwzo\r\nhJCc9Os8p3KLFgJe5DZX7vNVBByrmRm4QVI4Z9HKEJebnL6fYK0mX0fbCO9h\r\nis9MIaHAKlv/V/6zb05i/UfX5OqdTCkCZktAFrhmpGcqpE3V2hPHOQOK2V9Q\r\nQ49iiUEiCowLQxfmqZN8jOXkJ5jjGXWkmSMVxYVYlaVZH2v/VrmZAiFp/uOU\r\n2QJ8X+ubBrCsPgr3Zaa99ae3ExHqEUB5iyEV+/uCdZYzfZxvlsFbuaLmWerN\r\n8bc33Puc5DERwW/mlJ849pAJo3MoaYjQdLSX4bwLm+EXkQmsPzvQZJxXBp0N\r\n7Cz7jQ3jLAp1ySA0twdh12dP0/uNTlQcKYdpJFMTTolUSAKpElCBByvjW71t\r\nklQqTZeI23OQVN8lO7veEROHML8bC3Cq6zrpz1EpkuOgzyTZodBkB2r4cKxu\r\nBE1oHZ8Blt2+AUIBqzGQGtlOEXs6Ghr3LHY/9JOREvTLcgq8Hep3pBeuTlp7\r\nauuS+DYlNFLmOjyQ8/Q2HyZBN+yJc+sE7QSjvSUXhU3hT3wEsMaMM+Jekoeg\r\nOAdL95OYZPpAHZ8TdhBZDiAEDUEXFwYTFkw=\r\n=+wJX\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.7-next-1667938774.0_1667938810662_0.8577714774357967"},"_hasShrinkwrap":false},"0.7.7-next-1667939290.0":{"name":"@vuedx/typescript-plugin-vue","version":"0.7.7-next-1667939290.0","description":"TypeScript plugin for Vue","main":"index.js","module":"lib/standalone.mjs","types":"lib/index.d.ts","buildConfig":{"useMain":false,"sources":{"src/index.ts":[{"format":"module","file":"lib/standalone.cjs","bundle":{"platform":"node","format":"cjs","external":["typescript","typescript/lib/tsserverlibrary"]}},{"format":"module","file":"lib/standalone.mjs","bundle":{"platform":"node","format":"esm","external":["typescript","typescript/lib/tsserverlibrary"]}}],"types/3.x.d.ts":[{"format":"dts","file":"runtime/3.x.vuedx_runtime.d.ts"}]},"external":["typescript","typescript/lib/tsserverlibrary"]},"private":false,"keywords":["vue","vue-plugin","typescript","typescript-plugin"],"repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"funding":{"type":"individual","url":"https://github.com/sponsors/znck"},"license":"MIT","bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"},"homepage":"https://github.com/znck/vue-developer-experience#readme","dependencies":{"@vuedx/projectconfig":"0.7.4-next-1667939290.0","@vuedx/shared":"0.7.6-next-1667939290.0","@vuedx/template-ast-types":"0.7.5-next-1667939290.0","@vuedx/vue-virtual-textdocument":"0.7.7-next-1667939290.0","inversify":"^5.1.1","json5":"^2.2.0","node-ipc":"10.1.0","reflect-metadata":"^0.1.13"},"devDependencies":{"csstype":"^3.1.0","@vuedx/compiler-tsx":"0.8.2-next-1667939290.0","@types/web":"^0.0.56","@vue/runtime-core":"^3.2.39","quick-lru":"^6.0.1","vscode-languageserver-types":"^3.16.0","vue":"^0.12.2"},"readme":"<div align=\"center\" style=\"text-align: center; margin-bottom: 72px\">\n  <img src=\"./logo.png\" width=\"144\" style=\"margin-top: 72px; margin-bottom: 16px\" />\n  <h1>TypeScript Plugin for Vue</h1>\n  <p>Enables <code>.vue</code> file support in typescript (tsserver).</p>\n</div>\n\n## Goals\n\nThe goal of this plugin to improve developer experience in `.vue` files by providing features available in `.ts` file. To do so, a Vue SFC must:\n\n1. Act as an ES module.\n2. Type-check in `<template>` block.\n3. Provide completion in `<template>` expressions. Both directive and interpolation.\n4. Refactoring in `<script>` and `<template>` block.\n\n### Act as an ES module\n\nA `.vue` file should act as an ES module which means it can be imported in any `.ts` or `.js` file\nwithout a shim file for typescript support.\n\n### Type-check\n\nThe `<template>` block should be type-checked like TSX. The `tsc` utility does not support plugins; hence a dedicated type-check service (see `@vuedx/typecheck` package) is required.\n\n### Provide completion\n\nSemantic completion should be available in both `<script>` and `<template>` block. See the implementation section for details.\n\n### Refactoring\n\nThe `<script>` block should support all refactors as provided in a `.ts` file. The template `block` should support variable renaming.\n\n## Implementation\n\nAt the core of this plugin, there is a virtual file system that represents blocks in SFC as separate virtual files.\n\n### Virtual File System\n\n> The virtual file system is implemented in `@vuedx/vue-virtual-textdocument` package.\n\nA `.vue` file is a collection of different contexts collocated and wrapped in blocks. For example, in the following file (see Fig. 1), the `<script>` block contains TypeScript code while `<template>` block contains HTML-like DSL code.\n\n<figure>\n<figcaption>Fig. 1: component.vue file</figcaption>\n\n```vue\n<script lang=\"ts\">\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  },\n})\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n</template>\n```\n\n</figure>\n\nThis file can be represented with two separate files: `component.vue____script.ts` and `component.vue____template.vue-html`, we will call them virtual files as they do not exist on the file system.\n\n_Note: The dash character (-) in following code snippets represents whitespace._\n\n<figure>\n<figcaption>Fig. 2: <code>component.vue____script.ts</code> file</figcaption>\n\n```js\n------------------\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n  setup() {\n    return { foo: 0 }\n  }\n})\n```\n\n</figure>\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____template.ts</code> file</figcaption>\n\n```html\n------------------\n------------------------------------\n-------------------------------\n-----------\n---------------------\n---\n\n-- --------- ----------\n<div>{{ foo }}</div>\n```\n\n</figure>\n\nThe files are padded with spaces to have consistent positions with the source `.vue` file.\n\nA derived virtual file is generated from `<template>` block for `render()` function: `component.vue____render.ts`\n\n<figure>\n<figcaption>Fig. 3: <code>component.vue____render.ts</code> file</figcaption>\n\n```ts\nimport { h as _h } from 'vue'\nimport { JSX } from '<not decided yet>'\nimport _Ctx from './component.vue'\n\nexport function render(_ctx: _Ctx) {\n  return h(JSX.intrinsic.div, null, [_ctx.foo])\n}\n```\n\n</figure>\n\nWe will see `render()` function generation in further sections.\n\n### TS render function\n\n- Add type for render context.\n\n  ```ts\n  import _Ctx from './component.vue'\n\n  export function render(_ctx: _Ctx) {\n    // ...\n  }\n  ```\n\n- Convert HTML tags to `h()` calls.\n\n  ```html\n  <div>foo</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('div', null, ['foo'])\n  }\n  ```\n\n- Convert component tags to `h()` calls and add import statement\n\n  ```html\n  <template>\n    <CompA>foo</CompA>\n  </template>\n\n  <script>\n    import CompA from './comp-a.vue'\n\n    export default {\n      components: { CompA },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n  import CompA from './comp-a.vue'\n\n  export function render(/*...*/) {\n    return h(CompA, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Convert unresolved components.\n\n  ```html\n  <CompB>foo</CompB>\n  ```\n\n  ```ts\n  import { h, resolveComponent } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const CompB = resolveComponent('CompB') // Should return component type.\n\n    return h(CompB, null, {\n      default: () => ['foo'],\n    })\n  }\n  ```\n\n- Preserve web components\n\n  ```html\n  <web-comp>foo</web-comp>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(/*...*/) {\n    return h('web-comp', null, ['foo'])\n  }\n  ```\n\n- Convert `v-bind` and attrs to props object\n\n  ```html\n  <div :foo=\"test\" bar=\"test\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', { foo: _ctx.foo, bar: 'test' }, [])\n  }\n  ```\n\n- Covert `v-model` to props object\n\n  ```html\n  <input v-model=\"foo\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'input',\n      {\n        modelValue: _ctx.foo,\n        'onUpdate:modelValue': ($event) => (_ctx.foo = $event),\n      },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-on` to onXxx prop\n\n  ```html\n  <comp-a @foo=\"onFoo\" @bar=\"bar = $event\" />\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    // ...\n    return h(\n      CompA,\n      { onFoo: _ctx.onFoo, onBar: ($event) => (_ctx.bar = $event) },\n      {},\n    )\n  }\n  ```\n\n- Convert `v-show` to style prop\n\n  ```html\n  <div v-show=\"foo\" style=\"color: red\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      'div',\n      { style: [{ color: 'red' }, { display: _ctx.foo ? null : 'none' }] },\n      [],\n    )\n  }\n  ```\n\n- Convert `v-if`, `v-else-if`, and `v-else` to conditional expression\n\n  ```html\n  <div v-if=\"foo\">A</div>\n  <div v-else-if=\"bar\">B</div>\n  <div v-else>C</div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return _ctx.foo\n      ? h('div', {}, ['A'])\n      : _ctx.bar\n      ? h('div', {}, ['B'])\n      : h('div', {}, ['C'])\n  }\n  ```\n\n- Convert `v-for` to renderList\n\n  ```html\n  <div v-for=\"(item, index) of items\"></div>\n  ```\n\n  ```ts\n  import { h, renderList } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return renderList(_ctx.items, (item, index) => h('div', {}, []))\n  }\n  ```\n\n- Convert `v-text` and `v-html` to children\n\n  ```html\n  <div v-text=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n  ```html\n  <div v-html=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h('div', {}, [_ctx.foo])\n  }\n  ```\n\n- No runtime for `v-pre`\n\n- Drop `v-cloak` and `v-once`\n\n- Custom directive to import statements\n\n  ```html\n  <template>\n    <div v-custom:argument.modifier=\"foo\"></div>\n  </template>\n\n  <script>\n    import custom from './custom-directive'\n\n    export default {\n      directives: { custom },\n    }\n  </script>\n  ```\n\n  ```ts\n  import { h, withDirectives } from 'vue'\n  import custom from './custom-directive'\n\n  export function render(_ctx /*...*/) {\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `v-slot` to slot object\n\n- Unresolved custom directive\n\n  ```html\n  <div v-custom:argument.modifier=\"foo\"></div>\n  ```\n\n  ```ts\n  import { h, withDirectives, custom } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    const custom = resolveDirective('custom')\n\n    return withDirectives(h('div', {}, []), [\n      [custom, _ctx.foo, 'argument', { modifier: true }],\n    ])\n  }\n  ```\n\n- Convert `<slot>` to renderSlot\n\n  ```html\n  <Foo>\n    <slot name=\"xxx\" :foo=\"foo\" />\n  </Foo>\n  ```\n\n  ```ts\n  import { h, renderSlot } from 'vue'\n\n  export function render(_ctx /*...*/) {\n    return h(\n      Foo,\n      {},\n      {\n        default: () => renderSlot(_ctx.$slots, 'xxx', { foo: _ctx.foo }),\n      },\n    )\n  }\n  ```\n\n### Completion\n\nThere are two sources of completion in template:\n\n- Render Context\n- `v-for` or `v-slot` context\n\nWe have to provide completions from both sources at any position. Hence, we use cursor position to generate fake completion positions.\n\n```html\n<div v-for=\"item of items\">{{ foo + i█ }}</div>\n```\n\n```ts\nimport { h, renderList } from 'vue'\n\nexport function render(_ctx/*...*/) {\n  _ctx.i█\n\n  return renderList(_ctx.items, item => h('div', {}, [_ctx.foo + i█ ]))\n}\n```\n\nThe cursor after `foo + i` would generate two positions (marked by █) to get completion items.\n\n## Plugin Architecture\n\n![Plugin Architecture Diagram](./plugin-arch.png)\n\nThe plugin overrides few methods of the **Language Service Host**, the **Project Service** and the **Service Host**.\n\n### Project Service\n\nThe plugin adds `.vue` extension to the host configuration of the project service. This enables auto discovery of `.vue` files.\n\nThe downside of this approach is that it triggers reload for every project. It happens once (in the lifespan of the language server) when the plugin is activated.\n\n### Service Host\n\nService host provides filesystem APIs. We override some methods to provide seamless access to Vue virtual filesystem.\n\n#### `watchFile()`\n\nWe collect all virtual file watchers and subscribe them to the containing `.vue` file.\n\n#### `fileExists()`\n\nWe intercept `fileExists()` method to check virtual file existence in the Vue virtual filesystem.\n\n#### `readFile()`\n\nWe intercept `readFile()` method to read virtual files from the Vue virtual filesystem.\n\n### Language Service Host\n\nWe override module resolution algorithm to include `.vue` files.\n\n#### `getScriptFilename()`\n\nReplace `.vue` files to virtual files corresponding to `<script>` block and generated render function from `<template>` block.\n\n#### `resolveModuleNames()`\n\nResolve `.vue` imports to the virtual file corresponding to the `<script>` block of the `.vue` file.\n\n> Imports not ending in `.vue` are handled by default module resolution algorithm.\n\n## Language Server\n\nThe Vue Language Server acts as a proxy and routes requests to the correct virtual file.\n\nThe incoming requests are from real files (`.vue` or `.ts`) which are forwarded to the actual source file (virtual or real) in TypeScript program. This requires transforming source position to generated code position.\n\nOn response from the TypeScript Language Server, the response is processed to replace virtual file references with their containing `.vue` files. And generated code positions are transformed to source positions (to produce correct highlights in case of diagnostics).\n\n## Compiler Limitations\n\n### SourceMap accuracy\n\nTo provide diagnostics and completions, we need accurate source maps. Sadly the VLQ notation used in sourcemap v3 does not work well with ranges, e.g., `v-for`, `v-if` or any custom directive breaks sourcemap unexpectedly.\n\nWe need an API to implement custom sourcemap format. If we allow overriding `addMapping`, a simple implementation can be a bi-direction map of source-generated code ranges.\n\n> This is crucial for providing good developer experience and we need a better data structure to capture precise sourcemap.\n\n### Custom export function\n\nThe compiler hard codes the `render()` function export. However, we need to inject type annotation for `_ctx` argument.\n\n> There is a work-around for this as the generated `render()` function has arguments, i.e., `render(_ctx, _cache)`; which can be replaced with `render(_ctx: _Ctx··)` without affecting sourcemaps. (· represents space)\n\n## Further explorations\n\n### Detect `$slots` type interface\n\nWe can detect type interface of slots and that would help in completion of `v-slot` directive.\n\n### Provide block completion\n\n- Provide completion for `<script>`, `<template>`, `<style>`, `<preview>`, `<i18n>`\n\n### CSS Integration\n\n- Provide css identifier completion in `class` attribute\n- Declare CSS modules type render (maybe for script block too?)\n\n\n## Support\n\nThis package is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this package and other VueDX tools.\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.svg\">\n    <img src='https://cdn.jsdelivr.net/gh/znck/sponsors@main/sponsors.png'/>\n  </a>\n</p>\n","readmeFilename":"readme.md","_id":"@vuedx/typescript-plugin-vue@0.7.7-next-1667939290.0","_integrity":"sha512-ieaUPGVewlC8iBYfKanav4IyQPzSMUIE594xOsiYO0o1UQNM8uhhNr01zKTkHz3EvZux31J9az+Ve193B1kogg==","_resolved":"/tmp/88590025a26c9c0c4cbed9ac37ecba77/vuedx-typescript-plugin-vue-0.7.7-next-1667939290.0.tgz","_from":"file:vuedx-typescript-plugin-vue-0.7.7-next-1667939290.0.tgz","_nodeVersion":"18.12.0","_npmVersion":"8.19.2","dist":{"integrity":"sha512-ieaUPGVewlC8iBYfKanav4IyQPzSMUIE594xOsiYO0o1UQNM8uhhNr01zKTkHz3EvZux31J9az+Ve193B1kogg==","shasum":"2a528cccc66d2ca9e618cccfc325ecf73cd2a965","tarball":"https://registry.npmjs.org/@vuedx/typescript-plugin-vue/-/typescript-plugin-vue-0.7.7-next-1667939290.0.tgz","fileCount":112,"unpackedSize":12187595,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDa2rBJM40f8zLtZT7Ckqz/AVCGbvPjKFu5MXK50D4+swIhAN6PjDa5tK/eOQq8C/qRIGpXVoeOLGA7EEOyEz2pkJEv"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjarwAACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqVmw/9GNFCoWWYr54tAe/LkhRLzU5QrZk/oh0O8uVuCtX7AjrMiHwQ\r\nGdIyQb+eokhMT5SSCPawhctNZQtBsKQ/z7ODRcjvfhHH7/ZMFeLJ++XKmb86\r\nXiAm4HGaUDXVaIzcHzb6gpi7yw4JrEtaBECWSZqiKYPzs2LoZo0hCzJDskBy\r\n1F5pshgd/aTAI1dK5SyhOeQVq2xxv01qnznZR0e0bz8AOhIC/yLORSm8vjHV\r\nPH3DmtvTSCd0g7Zc775AT/sDF4Dv8sKRlGj1aFdRcMoDW2IGSCKdUYOJ2RMW\r\naIqtnHUvkbflpgWvaxVAmEYRPSsrZ+PVO/ARyovIAC50uOmHqZt0qUO47TRo\r\nPcRrG78imPwWWwPTVhnEkmbw9UjpLX/afvRkZ9Ef5Hbw1mG+ZUIbOE8ueZ5r\r\nVB6oWlhSwRnsDrHF2II00UCfdzyevIcxMLt3IKqsS6R1p0aAb4O+9tSfrz21\r\na7ET8n+TsN4sBl2DPJ+eJrmUwFGRKWY64RswnP2w8n53Cl1HSSSx8hCYOJMY\r\nt4oJxqvnQY8y21Is/1g9r9zFHjZ9sJbA7ypOtdzPg91wB+ie5G07DHHEvhk2\r\nysCFnF0ZSq7jJanNuluB9tdhFMNpPUJNRNnQfAxfch/qfkwsks78o9jn+o5Y\r\nr+OZ9MG97VmkvZgel7Z5V5CQzc97/ImxW+s=\r\n=Uiec\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"znck","email":"rahulkdn@gmail.com"},"directories":{},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/typescript-plugin-vue_0.7.7-next-1667939290.0_1667939328051_0.5894849079622577"},"_hasShrinkwrap":false}},"time":{"created":"2020-03-23T14:58:04.631Z","0.1.0":"2020-03-23T14:58:05.071Z","modified":"2022-11-08T20:28:48.387Z","0.1.0-alpha.0":"2020-04-09T11:22:06.341Z","0.1.0-alpha.1":"2020-04-09T16:55:20.251Z","0.1.0-alpha.2":"2020-04-09T20:23:44.046Z","0.1.0-alpha.3":"2020-04-11T05:14:06.612Z","0.1.0-alpha.4":"2020-04-11T08:09:54.051Z","0.1.0-alpha.5":"2020-04-12T09:39:31.757Z","0.1.0-alpha.7":"2020-04-16T16:51:31.890Z","0.1.0-alpha.8":"2020-04-19T13:15:24.745Z","0.1.0-alpha.9":"2020-05-23T09:57:04.531Z","0.1.0-alpha.10":"2020-05-23T10:17:53.389Z","0.1.0-alpha.11":"2020-05-23T11:25:27.490Z","0.1.0-alpha.12":"2020-05-23T15:10:47.175Z","0.1.0-alpha.13":"2020-07-08T07:18:55.751Z","0.1.1":"2020-08-03T07:58:19.551Z","0.1.2":"2020-08-03T11:05:11.628Z","0.1.3":"2020-08-03T11:06:37.845Z","0.1.4":"2020-08-03T13:22:50.023Z","0.1.5":"2020-08-04T10:01:09.168Z","0.2.0":"2020-08-08T12:27:38.575Z","0.2.1":"2020-08-08T14:52:22.525Z","0.2.2":"2020-08-09T01:31:37.328Z","0.2.3":"2020-08-09T01:52:29.830Z","0.2.4-0":"2020-09-16T02:00:41.628Z","0.3.1-insiders-1604106530.0":"2020-10-31T01:11:32.352Z","0.3.1-insiders-1604576237.0":"2020-11-05T11:39:28.144Z","0.3.1-insiders-1604891675.0":"2020-11-09T03:14:59.959Z","0.3.1-insiders-1605496438.0":"2020-11-16T03:14:25.297Z","0.3.1-insiders-1605961078.0":"2020-11-21T12:18:27.914Z","0.3.1-insiders-1606047354.0":"2020-11-22T12:16:27.525Z","0.3.1-insiders-1606101276.0":"2020-11-23T03:15:09.727Z","0.3.1-insiders-1606300525.0":"2020-11-25T10:35:56.364Z","0.3.1-insiders-1606311019.0":"2020-11-25T13:30:52.815Z","0.3.1-insiders-1606467106.0":"2020-11-27T08:52:17.517Z","0.3.1-insiders-1606884529.0":"2020-12-02T04:49:20.028Z","0.3.1-insiders-1607121235.0":"2020-12-04T22:34:30.009Z","0.3.1-insiders-1607543873.0":"2020-12-09T19:58:24.663Z","0.3.1-insiders-1607576406.0":"2020-12-10T05:00:38.127Z","0.3.1-insiders-1607576746.0":"2020-12-10T05:06:17.096Z","0.3.1-insiders-1607577772.0":"2020-12-10T05:23:22.118Z","0.3.1-insiders-1607631204.0":"2020-12-10T20:13:55.352Z","0.3.1-insiders-1607632537.0":"2020-12-10T20:36:08.403Z","0.3.1-insiders-1608185511.0":"2020-12-17T06:12:23.092Z","0.3.1-insiders-1608281809.0":"2020-12-18T08:57:18.948Z","0.3.1-insiders-1608285835.0":"2020-12-18T10:04:28.267Z","0.3.1-insiders-1608294809.0":"2020-12-18T12:33:58.495Z","0.3.1-insiders-1608632613.0":"2020-12-22T10:24:04.615Z","0.3.1-insiders-1608642006.0":"2020-12-22T13:00:35.896Z","0.3.1-insiders-1608679071.0":"2020-12-22T23:18:21.960Z","0.3.1-insiders-1608679989.0":"2020-12-22T23:33:43.566Z","0.3.1-insiders-1608682132.0":"2020-12-23T00:09:25.576Z","0.3.1-insiders-1609032938.0":"2020-12-27T01:36:07.552Z","0.3.1-insiders-1609034385.0":"2020-12-27T02:00:14.625Z","0.3.1-insiders-1609155664.0":"2020-12-28T11:41:32.284Z","0.4.1-insiders-1609180156.0":"2020-12-28T18:29:51.321Z","0.4.0":"2020-12-28T18:30:14.190Z","0.4.1-insiders-1609336775.0":"2020-12-30T14:00:10.589Z","0.4.1":"2020-12-30T14:01:46.837Z","0.4.2-insiders-1609376449.0":"2020-12-31T01:01:23.821Z","0.4.2-insiders-1609376781.0":"2020-12-31T01:06:54.642Z","0.4.2-insiders-1609385764.0":"2020-12-31T03:36:52.486Z","0.4.2-insiders-1609436485.0":"2020-12-31T17:42:00.413Z","0.4.2-insiders-1609479032.0":"2021-01-01T05:31:05.401Z","0.4.2-insiders-1609960000.0":"2021-01-06T19:07:16.405Z","0.4.2-insiders-1610169628.0":"2021-01-09T05:21:05.125Z","0.4.2-insiders-1610448877.0":"2021-01-12T10:55:14.858Z","0.5.1-insiders-1610450632.0":"2021-01-12T11:24:34.507Z","0.5.0":"2021-01-12T11:28:33.743Z","0.5.1-insiders-1610688008.0":"2021-01-15T05:20:47.466Z","0.5.1-insiders-1610735282.0":"2021-01-15T18:28:37.860Z","0.5.1-insiders-1610828338.0":"2021-01-16T20:19:38.043Z","0.6.1-insiders-1610883378.0":"2021-01-17T11:36:56.089Z","0.6.0":"2021-01-17T11:39:26.253Z","0.6.1-insiders-1610891537.0":"2021-01-17T13:52:54.307Z","0.6.1-insiders-1610911987.0":"2021-01-17T19:33:43.916Z","0.6.1-insiders-1611324083.0":"2021-01-22T14:02:03.938Z","0.6.1-insiders-1611498830.0":"2021-01-24T14:34:25.485Z","0.6.2-insiders-1611564162.0":"2021-01-25T08:43:20.633Z","0.6.3":"2021-01-25T09:18:52.093Z","0.6.4-insiders-1611829384.0":"2021-01-28T10:23:42.704Z","0.7.1-insiders-1623221784.0":"2021-06-09T06:57:05.786Z","0.7.0":"2021-06-09T06:58:08.470Z","0.7.1":"2021-06-09T07:45:27.943Z","0.7.2-insiders-1623224804.0":"2021-06-09T07:47:20.048Z","0.7.2":"2021-06-09T18:11:16.145Z","0.7.3-insiders-1623262375.0":"2021-06-09T18:13:30.602Z","0.7.3-insiders-1623383290.0":"2021-06-11T03:48:50.622Z","0.7.3-insiders-1623383952.0":"2021-06-11T04:01:22.328Z","0.7.3-insiders-1623384696.0":"2021-06-11T04:12:17.440Z","0.7.3":"2021-06-11T04:54:04.506Z","0.7.4-insiders-1623387961.0":"2021-06-11T05:06:38.733Z","0.7.5-insiders-1623390917.0":"2021-06-11T05:55:52.924Z","0.7.4":"2021-06-11T06:02:37.483Z","0.7.5-insiders-1623394946.0":"2021-06-11T07:03:05.576Z","0.7.5-insiders-1623402835.0":"2021-06-11T09:14:34.167Z","0.7.5-insiders-1630600136.0":"2021-09-02T16:29:38.494Z","0.7.5-insiders-1630601239.0":"2021-09-02T16:48:12.839Z","0.7.5-insiders-1630604709.0":"2021-09-02T17:45:50.483Z","0.7.5-next-1646032139.0":"2022-02-28T07:09:29.327Z","0.7.5-next-1646814663.0":"2022-03-09T08:31:29.792Z","0.7.5-next-1647274818.0":"2022-03-14T16:20:51.682Z","0.7.5-next-1647442110.0":"2022-03-16T14:49:00.493Z","0.7.5-next-1647674505.0":"2022-03-19T07:22:15.304Z","0.7.5-next-1647768616.0":"2022-03-20T09:30:47.446Z","0.7.5-next-1647933433.0":"2022-03-22T07:17:40.974Z","0.7.5-next-1648400394.0":"2022-03-27T17:00:24.695Z","0.7.5-next-1648409815.0":"2022-03-27T19:37:23.074Z","0.7.5-next-1648411566.0":"2022-03-27T20:06:34.453Z","0.7.5-next-1648440991.0":"2022-03-28T04:17:12.152Z","0.7.5-next-1648822539.0":"2022-04-01T14:16:10.703Z","0.7.5-next-1648824950.0":"2022-04-01T14:56:21.150Z","0.7.5-next-1649087720.0":"2022-04-04T15:55:52.475Z","0.7.5-next-1649225489.0":"2022-04-06T06:11:59.611Z","0.7.5-next-1649228283.0":"2022-04-06T06:58:35.049Z","0.7.5-next-1649315434.0":"2022-04-07T07:11:02.618Z","0.7.5-next-1649381954.0":"2022-04-08T01:39:44.189Z","0.7.5-next-1649388850.0":"2022-04-08T03:34:39.845Z","0.7.5-next-1649398416.0":"2022-04-08T06:14:09.452Z","0.7.5-next-1649493814.0":"2022-04-09T08:44:04.041Z","0.7.5-next-1649577134.0":"2022-04-10T07:52:48.150Z","0.7.5-next-1649578076.0":"2022-04-10T08:08:27.005Z","0.7.5-next-1649583602.0":"2022-04-10T09:40:33.706Z","0.7.5-next-1649585554.0":"2022-04-10T10:13:04.275Z","0.7.5-next-1649614433.0":"2022-04-10T18:14:21.624Z","0.7.5-next-1649653313.0":"2022-04-11T05:02:25.315Z","0.7.5-next-1649654649.0":"2022-04-11T05:24:37.940Z","0.7.5-next-1649655181.0":"2022-04-11T05:33:29.125Z","0.7.5-next-1649663515.0":"2022-04-11T07:52:25.603Z","0.7.5-next-1650753481.0":"2022-04-23T22:38:28.535Z","0.7.5":"2022-04-27T07:41:36.580Z","0.7.6-next-1651048177.0":"2022-04-27T08:30:09.486Z","0.7.6-next-1651050089.0":"2022-04-27T09:01:58.034Z","0.7.6-next-1651055813.0":"2022-04-27T10:37:33.196Z","0.7.6-next-1663917928.0":"2022-09-23T07:26:02.145Z","0.7.6-next-1663918844.0":"2022-09-23T07:41:23.356Z","0.7.6-next-1664761915.0":"2022-10-03T01:52:30.876Z","0.7.6-next-1664775821.0":"2022-10-03T05:44:09.870Z","0.7.6-next-1664852417.0":"2022-10-04T03:00:58.650Z","0.7.6-next-1665816659.0":"2022-10-15T06:51:33.076Z","0.7.6-next-1665904926.0":"2022-10-16T07:22:38.159Z","0.7.6-next-1665979403.0":"2022-10-17T04:04:00.326Z","0.7.6-next-1665995999.0":"2022-10-17T08:40:31.058Z","0.7.6-next-1666119500.0":"2022-10-18T18:59:01.523Z","0.7.6-next-1666207395.0":"2022-10-19T19:23:48.325Z","0.7.6-next-1666251997.0":"2022-10-20T07:47:08.918Z","0.7.6-next-1667343140.0":"2022-11-01T22:52:49.611Z","0.7.6-next-1667343481.0":"2022-11-01T22:58:38.718Z","0.7.6-next-1667345249.0":"2022-11-01T23:28:00.389Z","0.7.7-next-1667345594.0":"2022-11-01T23:33:47.750Z","0.7.6":"2022-11-01T23:33:57.170Z","0.7.7-next-1667540051.0":"2022-11-04T05:34:45.974Z","0.7.7-next-1667576550.0":"2022-11-04T15:43:10.715Z","0.7.7-next-1667925330.0":"2022-11-08T16:36:06.271Z","0.7.7-next-1667938774.0":"2022-11-08T20:20:10.885Z","0.7.7-next-1667939290.0":"2022-11-08T20:28:48.296Z"},"maintainers":[{"name":"znck","email":"rahulkdn@gmail.com"}],"description":"TypeScript plugin for Vue","keywords":["vue","vue-plugin","typescript","typescript-plugin"],"author":{"name":"Rahul Kadyan","email":"rahulkdn@gmail.com","url":"https://znck.me/"},"license":"MIT","readme":"","readmeFilename":"","homepage":"https://github.com/znck/vue-developer-experience#readme","repository":{"type":"git","url":"git+https://github.com/znck/vue-developer-experience.git"},"bugs":{"url":"https://github.com/znck/vue-developer-experience/issues"}}