diff --git a/.gitignore b/.gitignore index 0bab480..2e2fe19 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ codetations-react/src/applications/src/config.js **/.vscode/settings.json # Annotations for testing -codetations/ \ No newline at end of file +codetations/ +**/.claude/settings.local.json diff --git a/example_codetations_components/CommentComponent.tsx b/example_codetations_components/CommentComponent.tsx new file mode 100644 index 0000000..f59b565 --- /dev/null +++ b/example_codetations_components/CommentComponent.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +/** + * A simple comment component that renders markdown-formatted text + */ +export default function CommentComponent({ text, color = "#ffcc00" }) { + const style = { + padding: '8px 12px', + backgroundColor: color, + borderRadius: '4px', + maxWidth: '400px', + fontFamily: 'system-ui, -apple-system, sans-serif', + fontSize: '14px', + lineHeight: '1.5', + boxShadow: '0 2px 4px rgba(0,0,0,0.1)' + }; + + return ( +
+ {text || "Add your comment here"} +
+ ); +} \ No newline at end of file diff --git a/vscode-extension/.gitignore b/vscode-extension/.gitignore index 0b60dfa..1a43160 100644 --- a/vscode-extension/.gitignore +++ b/vscode-extension/.gitignore @@ -3,3 +3,5 @@ dist node_modules .vscode-test/ *.vsix +.DS_Store +.claude/ \ No newline at end of file diff --git a/vscode-extension/package-lock.json b/vscode-extension/package-lock.json index ac53854..ac6585d 100644 --- a/vscode-extension/package-lock.json +++ b/vscode-extension/package-lock.json @@ -11,6 +11,7 @@ "chokidar": "^3.6.0", "cors": "^2.8.5", "diff": "^8.0.0-beta", + "esbuild": "^0.19.4", "express": "^4.19.2", "openai": "^4.53.2", "ws": "^8.18.0" @@ -20,6 +21,8 @@ "@types/express": "^4.17.21", "@types/glob": "^7.1.3", "@types/node": "^22.0.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "@types/vscode": "^1.91.0", "@types/ws": "^8.5.12", "@typescript-eslint/eslint-plugin": "^4.14.1", @@ -27,6 +30,8 @@ "eslint": "^7.19.0", "glob": "^7.1.6", "prettier": "^2.2.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", "typescript": "^4.9.5", "vscode-test": "^1.5.0" }, @@ -137,6 +142,374 @@ "node": ">=4" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -340,6 +713,13 @@ "form-data": "^4.0.0" } }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -354,6 +734,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "18.3.20", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", + "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -1052,6 +1453,13 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -1214,6 +1622,44 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2189,6 +2635,19 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2634,6 +3093,33 @@ "node": ">= 0.8" } }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -2750,6 +3236,16 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -3387,6 +3883,144 @@ } } }, + "@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "optional": true + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -3564,6 +4198,12 @@ "form-data": "^4.0.0" } }, + "@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true + }, "@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -3576,6 +4216,22 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, + "@types/react": { + "version": "18.3.20", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", + "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true + }, "@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -3722,8 +4378,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "agent-base": { "version": "6.0.2", @@ -4054,6 +4709,12 @@ "which": "^2.0.1" } }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, "debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -4164,6 +4825,36 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, + "esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "requires": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -4894,6 +5585,15 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -5182,6 +5882,25 @@ "unpipe": "1.0.0" } }, + "react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -5258,6 +5977,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, "semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -5662,8 +6390,7 @@ "ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "requires": {} + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==" } } } diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 718acaf..fb24506 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -45,6 +45,10 @@ { "command": "codetations.moveSelected", "title": "Codetations: Move Selected" + }, + { + "command": "codetations.compileUserComponents", + "title": "Codetations: Compile User Components" } ], "menus": { @@ -96,6 +100,10 @@ "eslint": "^7.19.0", "glob": "^7.1.6", "prettier": "^2.2.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "typescript": "^4.9.5", "vscode-test": "^1.5.0" }, @@ -103,6 +111,7 @@ "chokidar": "^3.6.0", "cors": "^2.8.5", "diff": "^8.0.0-beta", + "esbuild": "^0.19.4", "express": "^4.19.2", "openai": "^4.53.2", "ws": "^8.18.0" diff --git a/vscode-extension/src/AnnotationTracker.ts b/vscode-extension/src/AnnotationTracker.ts index 64dd73b..663e4e6 100644 --- a/vscode-extension/src/AnnotationTracker.ts +++ b/vscode-extension/src/AnnotationTracker.ts @@ -141,9 +141,9 @@ export class AnnotationTracker implements vscode.Disposable { const { document: annDoc, ...rest } = ann; // Compute diff from global document to annotation's document let documentDiff = undefined; - if (annDoc !== globalDocument) { + if (annDoc && annDoc !== globalDocument) { try { - documentDiff = createPatch(document.fileName, globalDocument, annDoc); + documentDiff = createPatch(document.fileName, globalDocument || '', annDoc); } catch (e) { documentDiff = undefined; console.error("Error creating document diff:", e); @@ -154,9 +154,9 @@ export class AnnotationTracker implements vscode.Disposable { ...restOriginal } } = ann; let originalDocumentDiff = undefined; - if (originalDocument !== globalDocument) { + if (originalDocument && originalDocument !== globalDocument) { try { - originalDocumentDiff = createPatch(document.fileName, globalDocument, originalDocument); + originalDocumentDiff = createPatch(document.fileName, globalDocument || '', originalDocument); } catch (e) { originalDocumentDiff = undefined; console.error("Error creating original document diff:", e); diff --git a/vscode-extension/src/extension.ts b/vscode-extension/src/extension.ts index 6a434da..6cec2b2 100644 --- a/vscode-extension/src/extension.ts +++ b/vscode-extension/src/extension.ts @@ -6,6 +6,8 @@ import bodyParser from "body-parser"; import * as vscode from "vscode"; import fs from "fs"; import path from "path"; +import * as esbuild from "esbuild"; +import * as chokidar from "chokidar"; // import retagUpdate from "./server/retag"; import { SidebarProvider } from "./panels/AnnotationManagerPanel"; @@ -46,23 +48,244 @@ const runEndpointDictWithErrorHandlingOnPort = ( // Global annotation tracker instance export let annotationTracker: AnnotationTracker; +// Track discovered user components +export let userComponents: { [key: string]: { name: string; path: string }} = {}; + +// Function to discover user components +async function discoverUserComponents(): Promise<{ [key: string]: { name: string; path: string } }> { + const components: { [key: string]: { name: string; path: string } } = {}; + + // Get workspace folders + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders || workspaceFolders.length === 0) { + console.warn("No workspace folders found"); + return components; + } + + const workspacePath = workspaceFolders[0].uri.fsPath; + const componentsDir = path.join(workspacePath, 'codetations_components'); + const outDir = path.join(componentsDir, 'out'); + + console.log(`Looking for components in: ${componentsDir}`); + console.log(`Output directory: ${outDir}`); + + // Check if the components directory exists + if (!fs.existsSync(componentsDir)) { + console.warn(`Components directory does not exist: ${componentsDir}`); + return components; + } + + // Check if the output directory exists + if (!fs.existsSync(outDir)) { + console.warn(`Output directory does not exist: ${outDir}`); + return components; + } + + try { + // First, look for compiled JS files in the output directory + const compiledFiles = fs.readdirSync(outDir).filter(file => { + return file.endsWith('.js') && !file.startsWith('.'); + }); + + console.log(`Found ${compiledFiles.length} compiled files:`, compiledFiles); + + // Now look for source files to extract component names + const sourceFiles = fs.readdirSync(componentsDir).filter(file => { + const filePath = path.join(componentsDir, file); + const stats = fs.statSync(filePath); + return stats.isFile() && (file.endsWith('.tsx') || file.endsWith('.jsx')) && !file.startsWith('.'); + }); + + console.log(`Found ${sourceFiles.length} source files:`, sourceFiles); + + // Process each source file + for (const file of sourceFiles) { + // Check if we have a corresponding compiled file + const baseName = path.basename(file, path.extname(file)); + const compiledFile = compiledFiles.find(f => f.startsWith(baseName)); + + if (!compiledFile) { + console.warn(`No compiled file found for source: ${file}`); + continue; + } + + const filePath = path.join(componentsDir, file); + const fileContent = fs.readFileSync(filePath, 'utf-8'); + + // Parse the file to extract the component name + const componentNameMatch = fileContent.match(/export\s+default\s+(?:function\s+)?([A-Za-z0-9_]+)/); + const componentName = componentNameMatch ? componentNameMatch[1] : baseName; + + // Create the component entry + const key = baseName.toLowerCase(); + const compiledPath = path.join(outDir, compiledFile); + + // Create URI for the compiled file - this is what the webview will load + // STORE THE RAW PATH INSTEAD OF THE URI STRING + // const compiledUri = vscode.Uri.file(compiledPath).toString(); + + console.log(`Adding component: ${key} = ${componentName} at ${compiledPath}`); + + components[key] = { + name: componentName, + // Use the raw path + path: compiledPath + }; + } + + console.log(`Discovered ${Object.keys(components).length} components:`, components); + } catch (error) { + console.error(`Error discovering components: ${error instanceof Error ? error.message : String(error)}`); + } + + return components; +} + +// Function to compile user components with esbuild +async function compileUserComponents(): Promise { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders || workspaceFolders.length === 0) { + vscode.window.showErrorMessage('No workspace folder found.'); + return; + } + + const workspacePath = workspaceFolders[0].uri.fsPath; + const componentsDir = path.join(workspacePath, 'codetations_components'); + const outDir = path.join(componentsDir, 'out'); + + console.log(`Compiling components from: ${componentsDir}`); + console.log(`Output directory: ${outDir}`); + + // Check if the components directory exists + if (!fs.existsSync(componentsDir)) { + fs.mkdirSync(componentsDir, { recursive: true }); + vscode.window.showInformationMessage(`Created codetations_components directory at ${componentsDir}.`); + return; + } + + // Create output directory if it doesn't exist + if (!fs.existsSync(outDir)) { + fs.mkdirSync(outDir, { recursive: true }); + console.log(`Created output directory: ${outDir}`); + } + + // Find all component files + const files = fs.readdirSync(componentsDir).filter(file => { + const filePath = path.join(componentsDir, file); + const stats = fs.statSync(filePath); + return stats.isFile() && (file.endsWith('.tsx') || file.endsWith('.jsx')) && !file.startsWith('.'); + }); + + if (files.length === 0) { + vscode.window.showInformationMessage('No component files found in codetations_components directory.'); + return; + } + + console.log(`Found ${files.length} component files to compile:`, files); + + // Prepare entry points for esbuild + const entryPoints = files.map(file => path.join(componentsDir, file)); + + try { + // Run esbuild + console.log(`Starting esbuild with entry points:`, entryPoints); + + const result = await esbuild.build({ + entryPoints, + bundle: true, + outdir: outDir, + format: 'esm', + target: 'es2020', + // Bundle react and react-dom into the components to fix resolution error + external: [], + loader: { + '.tsx': 'tsx', + '.jsx': 'jsx', + }, + // Write metadata to help with debugging + metafile: true, + }); + + // Log build results if available + if (result.metafile) { + console.log("Build metadata:", result.metafile); + } + + vscode.window.showInformationMessage(`Compiled ${files.length} custom components successfully!`); + + // Discover components after compilation + console.log("Discovering compiled components..."); + userComponents = await discoverUserComponents(); + + // Notify all webviews to reload components + if (AnnotationManagerPanel.currentPanel) { + console.log("Sending refreshComponents to panel"); + AnnotationManagerPanel.currentPanel.refreshComponents(userComponents); + } + + // The sidebar view provider is not directly accessible through a global API + // A better approach is to use a reference stored at activation time + // For now we'll just rely on the panel notification + } catch (error) { + console.error("Build error:", error); + vscode.window.showErrorMessage(`Failed to compile components: ${error instanceof Error ? error.message : String(error)}`); + } +} + export function activate(context: vscode.ExtensionContext) { // Initialize the annotation tracker annotationTracker = new AnnotationTracker(context); context.subscriptions.push(annotationTracker); - // Register Sidebar Provider - const sidebarProvider = new SidebarProvider(context.extensionUri); - context.subscriptions.push( - vscode.window.registerWebviewViewProvider( - SidebarProvider.viewType, - sidebarProvider - ) - ); + // First, discover user components so they're available immediately + discoverUserComponents().then(components => { + userComponents = components; + + // Now register the sidebar provider with access to the components + const sidebarProvider = new SidebarProvider(context.extensionUri); + context.subscriptions.push( + vscode.window.registerWebviewViewProvider( + SidebarProvider.viewType, + sidebarProvider + ) + ); + + // Setup file watcher for components directory + const workspaceFolders = vscode.workspace.workspaceFolders; + if (workspaceFolders && workspaceFolders.length > 0) { + const workspacePath = workspaceFolders[0].uri.fsPath; + const componentsDir = path.join(workspacePath, 'codetations_components'); + + if (fs.existsSync(componentsDir)) { + const watcher = chokidar.watch(path.join(componentsDir, '*.{jsx,tsx}'), { + persistent: true, + ignoreInitial: true + }); + + // When files change, update the components list + watcher.on('add', async () => { + userComponents = await discoverUserComponents(); + // We don't auto-compile here, just update the list of available components + }).on('change', async () => { + userComponents = await discoverUserComponents(); + }).on('unlink', async () => { + userComponents = await discoverUserComponents(); + }); + + context.subscriptions.push({ + dispose: () => watcher.close() + }); + } + } + }); // Create the show annotations command const showAnnotationsCommand = commands.registerCommand("codetations.showAnnotations", () => { AnnotationManagerPanel.render(context.extensionUri); + // After rendering, send the user components using the panel's method + if (AnnotationManagerPanel.currentPanel) { + AnnotationManagerPanel.currentPanel.refreshComponents(userComponents); + } }); const chooseAnnotationType = () => { @@ -76,6 +299,10 @@ export function activate(context: vscode.ExtensionContext) { documentContent: editor?.document.getText(), }, }); + // After rendering, send the user components using the panel's method + if (AnnotationManagerPanel.currentPanel) { + AnnotationManagerPanel.currentPanel.refreshComponents(userComponents); + } }; // Create a command for adding annotations @@ -101,12 +328,24 @@ export function activate(context: vscode.ExtensionContext) { const moveSelectedCommand = commands.registerCommand("codetations.moveSelected", () => { AnnotationManagerPanel.currentPanel?.moveSelectedAnnotation(); }); + + // Command for compiling user components - now just does compilation + const compileUserComponentsCommand = commands.registerCommand("codetations.compileUserComponents", async () => { + await compileUserComponents(); + // After compilation, force update the components list + userComponents = await discoverUserComponents(); + // Send to any open panels using the panel's method + if (AnnotationManagerPanel.currentPanel) { + AnnotationManagerPanel.currentPanel.refreshComponents(userComponents); + } + }); context.subscriptions.push( showAnnotationsCommand, addAnnotationsCommand, removeAnnotationsCommand, setAnnotationColorCommand, - moveSelectedCommand + moveSelectedCommand, + compileUserComponentsCommand ); } \ No newline at end of file diff --git a/vscode-extension/src/panels/AnnotationManagerPanel.ts b/vscode-extension/src/panels/AnnotationManagerPanel.ts index 61dd774..d65b3b8 100644 --- a/vscode-extension/src/panels/AnnotationManagerPanel.ts +++ b/vscode-extension/src/panels/AnnotationManagerPanel.ts @@ -6,7 +6,7 @@ import * as path from "path"; import * as fs from "fs"; import { LMApiHandler } from "./LMApiHandler"; -import { annotationTracker } from "../extension"; +import { annotationTracker, userComponents } from "../extension"; import { Annotation } from "../AnnotationTracker"; import retagUpdate from "../server/retag"; import { BaseAnnotationView } from "./BaseAnnotationView"; @@ -36,6 +36,13 @@ export class AnnotationManagerPanel extends BaseAnnotationView { // Set the HTML content for the webview panel this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri); + + // Send user components immediately after the panel is created + // This ensures components are available as soon as the panel loads + setTimeout(() => { + // Call the new method to handle component refresh + this.refreshComponents(userComponents); + }, 500); // Short delay to make sure the webview is ready } /** @@ -49,6 +56,22 @@ export class AnnotationManagerPanel extends BaseAnnotationView { // If the webview panel already exists reveal it AnnotationManagerPanel.currentPanel._panel.reveal(ViewColumn.Two, true); } else { + // Get workspace root + const workspaceFolders = vscode.workspace.workspaceFolders; + const workspaceRootUri = workspaceFolders ? workspaceFolders[0].uri : undefined; + + // Define allowed resource roots + const localResourceRoots = [ + Uri.joinPath(extensionUri, "out"), + Uri.joinPath(extensionUri, "webview-ui/build") + ]; + if (workspaceRootUri) { + // Add the user components output directory in the workspace + localResourceRoots.push(Uri.joinPath(workspaceRootUri, 'codetations_components', 'out')); + } else { + console.warn("Workspace root not found, cannot set localResourceRoots for user components."); + } + // If a webview panel does not already exist create and show a new one const panel = window.createWebviewPanel( "showAnnotations", @@ -57,10 +80,8 @@ export class AnnotationManagerPanel extends BaseAnnotationView { { enableScripts: true, retainContextWhenHidden: true, - localResourceRoots: [ - Uri.joinPath(extensionUri, "out"), - Uri.joinPath(extensionUri, "webview-ui/build"), - ], + // Use the defined localResourceRoots + localResourceRoots: localResourceRoots, } ); @@ -120,6 +141,43 @@ export class AnnotationManagerPanel extends BaseAnnotationView { endOffset ); } + + /** + * Sends an object as a JSON message to the webview. + * @param message The message object to send. + */ + public sendMessageObject(message: any) { + if (this._panel) { + this._panel.webview.postMessage(message); + } + } + + /** + * Converts component paths to webview URIs and sends them to the panel. + * @param components The user components object with fsPaths. + */ + public refreshComponents(components: typeof userComponents) { + if (!this._panel) { + console.warn("Attempted to refresh components on a disposed panel."); + return; + } + + const webview = this._panel.webview; + const webviewUserComponents = Object.entries(components).reduce((acc, [key, component]) => { + try { + const webviewUri = webview.asWebviewUri(vscode.Uri.file(component.path)); + acc[key] = { ...component, path: webviewUri.toString() }; + } catch (e) { + console.error(`Failed to create webview URI for ${component.path} in refreshComponents:`, e); + } + return acc; + }, {} as typeof userComponents); + + this.sendMessageObject({ + command: 'refreshComponents', + components: webviewUserComponents + }); + } } export class SidebarProvider implements vscode.WebviewViewProvider { @@ -140,13 +198,27 @@ export class SidebarProvider implements vscode.WebviewViewProvider { ) { this._view = webviewView; + // Get workspace root + const workspaceFolders = vscode.workspace.workspaceFolders; + const workspaceRootUri = workspaceFolders ? workspaceFolders[0].uri : undefined; + + // Define allowed resource roots + const sidebarLocalResourceRoots = [ + vscode.Uri.joinPath(this._extensionUri, "out"), + vscode.Uri.joinPath(this._extensionUri, "webview-ui/build") + ]; + if (workspaceRootUri) { + // Add the user components output directory in the workspace + sidebarLocalResourceRoots.push(vscode.Uri.joinPath(workspaceRootUri, 'codetations_components', 'out')); + } else { + console.warn("Workspace root not found, cannot set localResourceRoots for user components in sidebar."); + } + webviewView.webview.options = { enableScripts: true, // retainContextWhenHidden: true, - localResourceRoots: [ - vscode.Uri.joinPath(this._extensionUri, "out"), - vscode.Uri.joinPath(this._extensionUri, "webview-ui/build"), - ], + // Use the defined localResourceRoots + localResourceRoots: sidebarLocalResourceRoots, }; // Initialize the LM API Handler @@ -168,6 +240,29 @@ export class SidebarProvider implements vscode.WebviewViewProvider { this._loadAnnotationsForActiveEditor(); } + // Send user components to the webview on initialization + setTimeout(() => { + // Convert fsPaths to webview URIs for the sidebar + const webviewUserComponents = Object.entries(userComponents).reduce((acc, [key, component]) => { + try { + // Use the sidebar's webview instance + const webviewUri = webviewView.webview.asWebviewUri(vscode.Uri.file(component.path)); + acc[key] = { ...component, path: webviewUri.toString() }; + } catch (e) { + console.error(`Failed to create webview URI for sidebar component ${component.path}:`, e); + // Optionally skip this component or handle the error + } + return acc; + }, {} as typeof userComponents); + + this.sendMessageObject({ + command: 'refreshComponents', + components: webviewUserComponents // Send the converted components + }); + // Call the new method to handle component refresh + // this.refreshComponents(userComponents); + }, 500); + // Handle panel disposal webviewView.onDidDispose(() => { while (this._disposables.length) { @@ -215,15 +310,29 @@ export class SidebarProvider implements vscode.WebviewViewProvider { const nonce = getNonce(); + // Define the import map + const importMap = { + imports: { + "react": scriptUri.toString(), // Map "react" to the main script URI + "react-dom": scriptUri.toString(), // Map "react-dom" to the main script URI + "react-dom/client": scriptUri.toString() // Often needed as well + } + }; + return /*html*/ ` - + Annotations + + +
@@ -532,7 +641,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider { */ public sendMessageObject(message: any) { if (this._view) { - this._view.webview.postMessage(JSON.stringify(message)); + this._view.webview.postMessage(message); } } @@ -547,13 +656,13 @@ export class SidebarProvider implements vscode.WebviewViewProvider { } this._view.webview.postMessage( - JSON.stringify({ + { command: "addAnnotation", data: { start: editor.document.offsetAt(editor.selection.start), end: editor.document.offsetAt(editor.selection.end), }, - }) + } ); } @@ -564,9 +673,9 @@ export class SidebarProvider implements vscode.WebviewViewProvider { if (!this._view) return; this._view.webview.postMessage( - JSON.stringify({ + { command: "removeAnnotation", - }) + } ); } @@ -580,12 +689,12 @@ export class SidebarProvider implements vscode.WebviewViewProvider { vscode.window.showInputBox({ prompt: "Enter a color" }).then((color) => { if (color && this._view) { this._view.webview.postMessage( - JSON.stringify({ + { command: "setAnnotationColor", data: { color: color, }, - }) + } ); } }); diff --git a/vscode-extension/src/panels/BaseAnnotationView.ts b/vscode-extension/src/panels/BaseAnnotationView.ts index 950f894..e73a097 100644 --- a/vscode-extension/src/panels/BaseAnnotationView.ts +++ b/vscode-extension/src/panels/BaseAnnotationView.ts @@ -174,6 +174,21 @@ export abstract class BaseAnnotationView { return; } const { annotation: newAnnotation } = message.data; + + // Ensure document and original document are properly defined + if (!newAnnotation.document) { + newAnnotation.document = editor.document.getText(); + } + + if (!newAnnotation.original || !newAnnotation.original.document) { + newAnnotation.original = { + ...newAnnotation.original || {}, + document: editor.document.getText(), + start: newAnnotation.start, + end: newAnnotation.end + }; + } + annotationTracker.addAnnotation(editor.document, newAnnotation); return; @@ -403,8 +418,9 @@ export abstract class BaseAnnotationView { * Sends a message to the webview context. */ public sendMessageObject(message: any) { - // Implement in child classes - this.webview.postMessage(JSON.stringify(message)); + if (this.webview) { + this.webview.postMessage(message); + } } /** @@ -417,26 +433,22 @@ export abstract class BaseAnnotationView { return; } - this.webview.postMessage( - JSON.stringify({ - command: "addAnnotation", - data: { - start: editor.document.offsetAt(editor.selection.start), - end: editor.document.offsetAt(editor.selection.end), - }, - }) - ); + this.webview.postMessage({ + command: "addAnnotation", + data: { + start: editor.document.offsetAt(editor.selection.start), + end: editor.document.offsetAt(editor.selection.end), + }, + }); } /** * Handles the command to remove the selected annotation */ public removeAnnotation(): void { - this.webview.postMessage( - JSON.stringify({ - command: "removeAnnotation", - }) - ); + this.webview.postMessage({ + command: "removeAnnotation", + }); } /** @@ -446,14 +458,12 @@ export abstract class BaseAnnotationView { // Get the color from the user vscode.window.showInputBox({ prompt: "Enter a color" }).then((color) => { if (color) { - this.webview.postMessage( - JSON.stringify({ - command: "setAnnotationColor", - data: { - color: color, - }, - }) - ); + this.webview.postMessage({ + command: "setAnnotationColor", + data: { + color: color, + }, + }); } }); } diff --git a/vscode-extension/src/panels/SidebarProvider.ts b/vscode-extension/src/panels/SidebarProvider.ts index 36a302c..a376e56 100644 --- a/vscode-extension/src/panels/SidebarProvider.ts +++ b/vscode-extension/src/panels/SidebarProvider.ts @@ -1,5 +1,6 @@ import * as vscode from "vscode"; import { BaseAnnotationView } from "./BaseAnnotationView"; +import { userComponents } from "../extension"; export class SidebarProvider extends BaseAnnotationView implements vscode.WebviewViewProvider { public static readonly viewType = "codetations-annotations"; @@ -43,6 +44,14 @@ export class SidebarProvider extends BaseAnnotationView implements vscode.Webvie this._loadAnnotationsForActiveEditor(); } + // Send user components to the webview on initialization + setTimeout(() => { + this.sendMessageObject({ + command: 'refreshComponents', + components: userComponents + }); + }, 500); + // Handle panel disposal webviewView.onDidDispose(() => { this.dispose(); diff --git a/vscode-extension/webview-ui/package-lock.json b/vscode-extension/webview-ui/package-lock.json index 2953bd8..90d97a8 100644 --- a/vscode-extension/webview-ui/package-lock.json +++ b/vscode-extension/webview-ui/package-lock.json @@ -718,6 +718,10 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/codetations": { + "resolved": "", + "link": true + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1322,10 +1326,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/codetations": { - "resolved": "", - "link": true - }, "node_modules/html-url-attributes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz", @@ -3128,364 +3128,8 @@ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==" }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "requires": { - "ms": "2.1.2" - } - }, - "decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", - "requires": { - "character-entities": "^2.0.0" - } - }, - "dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" - }, - "devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "requires": { - "dequal": "^2.0.0" - } - }, - "electron-to-chromium": { - "version": "1.4.37", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.37.tgz", - "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg==", - "dev": true - }, - "esbuild": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", - "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", - "dev": true, - "requires": { - "@esbuild/linux-loong64": "0.14.54", - "esbuild-android-64": "0.14.54", - "esbuild-android-arm64": "0.14.54", - "esbuild-darwin-64": "0.14.54", - "esbuild-darwin-arm64": "0.14.54", - "esbuild-freebsd-64": "0.14.54", - "esbuild-freebsd-arm64": "0.14.54", - "esbuild-linux-32": "0.14.54", - "esbuild-linux-64": "0.14.54", - "esbuild-linux-arm": "0.14.54", - "esbuild-linux-arm64": "0.14.54", - "esbuild-linux-mips64le": "0.14.54", - "esbuild-linux-ppc64le": "0.14.54", - "esbuild-linux-riscv64": "0.14.54", - "esbuild-linux-s390x": "0.14.54", - "esbuild-netbsd-64": "0.14.54", - "esbuild-openbsd-64": "0.14.54", - "esbuild-sunos-64": "0.14.54", - "esbuild-windows-32": "0.14.54", - "esbuild-windows-64": "0.14.54", - "esbuild-windows-arm64": "0.14.54" - } - }, - "esbuild-android-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", - "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", - "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", - "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", - "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", - "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", - "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", - "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", - "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", - "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", - "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", - "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", - "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", - "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", - "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", - "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", - "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", - "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", - "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", - "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", - "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", - "dev": true, - "optional": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==" - }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "exenv-es6": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", - "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "file-selector": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", - "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", - "requires": { - "tslib": "^2.4.0" - }, - "dependencies": { - "tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - } - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "hast-util-to-jsx-runtime": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", - "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", - "requires": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - } - }, - "hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "requires": { - "@types/hast": "^3.0.0" - } - }, - "codetations": { - "version": "file:", + "codetations": { + "version": "file:", "requires": { "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", @@ -5183,6 +4827,362 @@ } } }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "requires": { + "ms": "2.1.2" + } + }, + "decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "requires": { + "character-entities": "^2.0.0" + } + }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + }, + "devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "requires": { + "dequal": "^2.0.0" + } + }, + "electron-to-chromium": { + "version": "1.4.37", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.37.tgz", + "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg==", + "dev": true + }, + "esbuild": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", + "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", + "dev": true, + "requires": { + "@esbuild/linux-loong64": "0.14.54", + "esbuild-android-64": "0.14.54", + "esbuild-android-arm64": "0.14.54", + "esbuild-darwin-64": "0.14.54", + "esbuild-darwin-arm64": "0.14.54", + "esbuild-freebsd-64": "0.14.54", + "esbuild-freebsd-arm64": "0.14.54", + "esbuild-linux-32": "0.14.54", + "esbuild-linux-64": "0.14.54", + "esbuild-linux-arm": "0.14.54", + "esbuild-linux-arm64": "0.14.54", + "esbuild-linux-mips64le": "0.14.54", + "esbuild-linux-ppc64le": "0.14.54", + "esbuild-linux-riscv64": "0.14.54", + "esbuild-linux-s390x": "0.14.54", + "esbuild-netbsd-64": "0.14.54", + "esbuild-openbsd-64": "0.14.54", + "esbuild-sunos-64": "0.14.54", + "esbuild-windows-32": "0.14.54", + "esbuild-windows-64": "0.14.54", + "esbuild-windows-arm64": "0.14.54" + } + }, + "esbuild-android-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", + "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", + "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", + "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", + "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", + "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", + "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", + "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", + "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", + "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", + "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", + "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", + "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", + "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", + "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", + "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", + "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", + "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", + "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", + "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", + "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==" + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "exenv-es6": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "requires": { + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "hast-util-to-jsx-runtime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "requires": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + } + }, + "hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "requires": { + "@types/hast": "^3.0.0" + } + }, "html-url-attributes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz", diff --git a/vscode-extension/webview-ui/src/App.css b/vscode-extension/webview-ui/src/App.css index 67d90e7..55fbe3a 100644 --- a/vscode-extension/webview-ui/src/App.css +++ b/vscode-extension/webview-ui/src/App.css @@ -44,6 +44,127 @@ main { z-index: 1; } +/* Styles for the annotation type selector */ +.add-note-banner { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + background-color: #f8f9fa; + border-bottom: 1px solid #dee2e6; + padding: 16px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(4px); + display: flex; + flex-direction: column; + gap: 12px; +} + +.add-note-title { + font-size: 16px; + font-weight: 600; + margin-bottom: 10px; +} + +.add-note-tools { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); + gap: 8px; + max-height: 200px; + overflow-y: auto; + padding-right: 5px; +} + +.add-note-tool { + background-color: #f0f0f0; + border: 1px solid #ddd; + border-radius: 4px; + padding: 8px 12px; + cursor: pointer; + transition: all 0.2s ease; + text-align: center; + font-size: 14px; +} + +.add-note-tool:hover { + background-color: #e6e6e6; + border-color: #bbb; +} + +.add-note-tool.selected { + background-color: #0078D4; + color: white; + border-color: #0078D4; +} + +.add-note-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + margin-top: 8px; +} + +.add-note-actions button { + padding: 6px 14px; + border-radius: 4px; + border: 1px solid #ddd; + cursor: pointer; + font-size: 14px; + background-color: #f0f0f0; +} + +.add-note-actions button:hover { + background-color: #e6e6e6; +} + +.add-note-actions button:last-child { + background-color: #0078D4; + color: white; + border-color: #0078D4; +} + +.add-note-actions button:last-child:hover { + background-color: #006cc1; +} + +.add-note-actions button:last-child:disabled { + background-color: #cccccc; + border-color: #bbbbbb; + cursor: not-allowed; +} + +.no-annotations { + padding: 20px; + text-align: center; + color: #666; + font-style: italic; +} + +.retag-banner { + padding: 10px; + margin-bottom: 10px; + background-color: #ffe0e0; + border-radius: 4px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.retag-banner button { + padding: 4px 10px; + border-radius: 4px; + border: 1px solid #d32f2f; + background-color: #ffffff; + color: #d32f2f; + cursor: pointer; +} + +.retag-banner button:hover { + background-color: #d32f2f; + color: white; +} + /* textarea { resize: vertical; width: 280px; diff --git a/vscode-extension/webview-ui/src/App.tsx b/vscode-extension/webview-ui/src/App.tsx index 05e9390..83910ea 100644 --- a/vscode-extension/webview-ui/src/App.tsx +++ b/vscode-extension/webview-ui/src/App.tsx @@ -2,7 +2,7 @@ import { vscode } from "./utilities/vscode"; import "./App.css"; import Annotation from "./Annotation"; import { tools, toolNames } from "./tools"; -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect, useRef, Suspense, lazy } from "react"; interface AnnotationUpdate { document?: string; @@ -19,10 +19,51 @@ type ToolTypes = { [key: string]: React.FC; }; -const toolTypes: ToolTypes = { +// Base tool types from our internal components +const baseToolTypes: ToolTypes = { ...tools, }; +// Dynamic user-defined components will be stored here +let userToolTypes: ToolTypes = {}; +let userToolNames: { [key: string]: string } = {}; + +// Function to dynamically load a user component +function loadUserComponent(componentPath: string) { + console.log(`Attempting to load component from path: ${componentPath}`); + + try { + // Convert file:// URL to a relative path if needed + let path = componentPath; + if (path.startsWith('file://')) { + // Remove file:// prefix and convert to a format that works with dynamic imports + path = path.replace(/^file:\/\//, ''); + console.log(`Converted path to: ${path}`); + } + + // For testing purposes, let's also log what we're trying to import + console.log(`Dynamic import path: ${path}`); + + // Dynamic imports have different behavior in different environments + // In vite/browser context, they need to be relative or absolute URLs + return lazy(() => { + console.log(`Actually importing: ${path}`); + return import(/* @vite-ignore */ path) + .then(module => { + console.log(`Import succeeded for ${path}, module:`, module); + return module; + }) + .catch(err => { + console.error(`Import failed for ${path}:`, err); + throw err; + }); + }); + } catch (error) { + console.error(`Error setting up dynamic import for ${componentPath}:`, error); + return null; + } +} + function AnnotationEditorContainer(props: { value: Annotation; setValue: (value: AnnotationUpdate) => void; @@ -33,30 +74,41 @@ function AnnotationEditorContainer(props: { onDelete: (id: string) => void; }) { const { value, setValue, setSelectedAnnotationId, onDelete } = props; + + // Combine base and user-defined tool types + const allToolTypes = { ...baseToolTypes, ...userToolTypes }; + const ToolComponent = allToolTypes[value.tool]; return (
- {toolTypes[value.tool]?.({ - value, - setValue: (v: AnnotationUpdate) => - setValue({ ...value, document: v.document, metadata: v.metadata }), - utils: { - getText: () => value.document.slice(value.start, value.end), - setText: (newText: string) => { - setValue({ - document: - value.document.slice(0, value.start) + newText + value.document.slice(value.end), - metadata: value.metadata, - }); - }, - setMetadata: (newMetadata: any) => { - setValue({ - document: value.document, - metadata: { ...value.metadata, ...newMetadata }, - }); - }, - }, - })} + {ToolComponent ? ( + Loading component...
}> + + setValue({ ...value, document: v.document, metadata: v.metadata }) + } + utils={{ + getText: () => value.document.slice(value.start, value.end), + setText: (newText: string) => { + setValue({ + document: + value.document.slice(0, value.start) + newText + value.document.slice(value.end), + metadata: value.metadata, + }); + }, + setMetadata: (newMetadata: any) => { + setValue({ + document: value.document, + metadata: { ...value.metadata, ...newMetadata }, + }); + }, + }} + /> + + ) : ( +
Component not found: {value.tool}
+ )} ); } @@ -292,54 +344,26 @@ function AddNoteBanner(props: { onCancel: () => void; toolTypes: ToolTypes; }) { - const { onConfirm, selectedTool, setSelectedTool, toolTypes } = props; - + // Combine base and user tool names + const allToolNames = { ...toolNames, ...userToolNames }; + return ( -
-
- Add Note: - +
+
Choose annotation type:
+
+ {Object.entries(allToolNames).map(([key, name]) => ( +
props.setSelectedTool(key)}> + {name} +
+ ))}
-
- +
@@ -347,31 +371,128 @@ function AddNoteBanner(props: { } function App() { - // State for document and annotations - const [documentUri, setDocumentUri] = useState(undefined); - const [documentText, setDocumentText] = useState(""); const [annotations, setAnnotations] = useState([]); - - // UI state - const [charNum, setCharNum] = useState(undefined); - const [selectedAnnotationId, setSelectedAnnotationId] = useState(undefined); + const [documentText, setDocumentText] = useState(""); + const [documentUri, setDocumentUri] = useState(""); const [hoveredAnnotationId, setHoveredAnnotationId] = useState(undefined); - const [chooseAnnotationType, setChooseAnnotationType] = useState(false); - const [confirmAnnotation, setConfirmAnnotation] = useState(false); - - // Annotation creation state - const [start, setStart] = useState(undefined); - const [end, setEnd] = useState(undefined); - const defaultTool = Object.keys(toolTypes).length > 0 ? Object.keys(toolTypes)[0] : undefined; - const [newTool, setNewTool] = useState(defaultTool); - - // Track current selection in editor - const [currentSelection, setCurrentSelection] = useState<{start: number, end: number} | null>(null); - const hasSelection = currentSelection && currentSelection.start !== currentSelection.end; + const [selectedAnnotationId, setSelectedAnnotationId] = useState(undefined); + const [charNum, setCharNum] = useState(undefined); + const [isOutOfSync, setIsOutOfSync] = useState(false); + const [isAdding, setIsAdding] = useState(false); + const [selectedTool, setSelectedTool] = useState(undefined); + const [showRetagBanner, setShowRetagBanner] = useState(false); + const [addingAnnotationRange, setAddingAnnotationRange] = useState< + { start: number; end: number } | undefined + >(undefined); - const showRetagBanner = annotations.some((annotation) => - isAnnotationOutOfSync(annotation, documentText) - ); + // ... rest of the existing code ... + + useEffect(() => { + const handleMessage = (event: MessageEvent) => { + const message = event.data; + console.log("Received message:", message); + + switch (message.command) { + case "initialize": + setDocumentText(message.data.documentText); + setDocumentUri(message.data.documentUri); + setAnnotations(message.data.annotations); + break; + case "refreshComponents": + // Load user-defined components + loadUserDefinedComponents(message.components); + break; + case "addAnnotation": + // Handle add annotation request + setIsAdding(true); + setAddingAnnotationRange({ + start: message.data.start, + end: message.data.end + }); + break; + case "updateAnnotations": + // Update annotations list + if (message.data.documentUri === documentUri) { + setAnnotations(message.data.annotations || []); + if (message.data.documentText) { + setDocumentText(message.data.documentText); + } + } + break; + case "handleCursorPositionChange": + // Handle cursor position change + setCharNum(message.data.position); + break; + case "chooseAnnotationType": + // Set up for annotation type selection + setIsAdding(true); + setAddingAnnotationRange({ + start: message.data.start, + end: message.data.end + }); + if (message.data.documentContent) { + setDocumentText(message.data.documentContent); + } + break; + case "removeAnnotation": + // Handled by parent, but we may want to update UI state + if (selectedAnnotationId === message.data.annotationId) { + setSelectedAnnotationId(undefined); + } + break; + case "setAnnotationColor": + // Update is handled by the extension + break; + // ... existing cases ... + } + }; + + // Register the event listener + window.addEventListener("message", handleMessage); + + // Clean up the event listener when the component unmounts + return () => { + window.removeEventListener("message", handleMessage); + }; + }, []); + + // Function to load user-defined components + const loadUserDefinedComponents = (components: { [key: string]: { name: string; path: string } }) => { + console.log("loadUserDefinedComponents called with:", components); + + const newUserToolTypes: ToolTypes = {}; + const newUserToolNames: { [key: string]: string } = {}; + + // Process each component + if (!components || Object.keys(components).length === 0) { + console.warn("No components received in loadUserDefinedComponents"); + return; + } + + for (const [key, component] of Object.entries(components)) { + console.log(`Processing component: ${key} with path: ${component.path}`); + try { + // Load the component dynamically + const UserComponent = loadUserComponent(component.path); + if (UserComponent) { + console.log(`Successfully loaded component: ${key}`); + newUserToolTypes[key] = UserComponent; + newUserToolNames[key] = component.name; + } else { + console.warn(`Component loaded but is null/undefined: ${key}`); + } + } catch (error) { + console.error(`Failed to load component ${component.name}:`, error); + } + } + + // Update the user components + userToolTypes = newUserToolTypes; + userToolNames = newUserToolNames; + + console.log("Updated user components:", Object.keys(userToolTypes)); + console.log("Updated user tool names:", userToolNames); + }; // Utility functions const showErrorMessage = (error: string) => { @@ -390,37 +511,23 @@ function App() { }); }; - const handleChooseAnnType = (start: number, end: number, documentContent: string) => { - setChooseAnnotationType(true); - setStart(start); - setEnd(end); - setDocumentText(documentContent); - }; - - const handleAddAnnotation = (start: number, end: number) => { - setStart(start); - setEnd(end); - // Instead of showing confirmation dialog, just set hasSelection to enable the banner - }; - - // Rename this function to be clearer since it now directly adds the annotation const handleCreateAnnotation = () => { - // Update state once the add note button is clicked - setConfirmAnnotation(false); - setChooseAnnotationType(false); - setCurrentSelection(null); - - if (start === undefined || end === undefined) { + // Update state + setIsAdding(false); + + if (!addingAnnotationRange) { showErrorMessage("Error adding annotations: no highlighted text"); return; } + const { start, end } = addingAnnotationRange; + if (start === end) { showErrorMessage("Error adding annotations: selection must not be empty"); return; } - if (!newTool) { + if (!selectedTool) { showErrorMessage("Error adding annotations: no tool selected"); return; } @@ -454,7 +561,7 @@ function App() { start, end, document: documentText, - tool: newTool, + tool: selectedTool, metadata: { color: annotationColor }, @@ -484,227 +591,37 @@ function App() { } }; - const handleRemoveAnnotation = () => { - if (!selectedAnnotationId) { - showErrorMessage("Error removing annotations: no selected annotation"); - return; - } - - vscode.postMessage({ - command: "removeAnnotation", - data: { annotationId: selectedAnnotationId } - }); - - setSelectedAnnotationId(undefined); - }; - - const handleSetAnnotationColor = (color: string) => { - if (!selectedAnnotationId) { - showErrorMessage("Error setting annotation color: no selected annotation"); - return; - } - - vscode.postMessage({ - command: "setAnnotationColor", - data: { - annotationId: selectedAnnotationId, - color - } - }); - }; - const handleCancelAddAnnotation = () => { - setConfirmAnnotation(false); - setStart(undefined); - setEnd(undefined); + setIsAdding(false); + setAddingAnnotationRange(undefined); }; + // Add a useEffect to check if annotations need retagging useEffect(() => { - // Message handler for communication with extension - const handleMessage = (event: MessageEvent) => { - const message = JSON.parse(event.data); - console.debug("Received message:", message); - - switch (message.command) { - case "initialize": - // Initialize the UI with document data and annotations - setDocumentUri(message.data.documentUri); - setDocumentText(message.data.documentText); - setAnnotations(message.data.annotations || []); - return; - - case "updateAnnotations": - // Update annotations from extension - if (message.data.documentUri === documentUri) { - setAnnotations(message.data.annotations || []); - setDocumentText(message.data.documentText); - } - return; - - case "handleCursorPositionChange": - // Handle cursor position change - setCharNum(message.data.position); - // Track selection state - if (message.data.selection) { - const selection = message.data.selection; - if (selection.start === selection.end) { - setCurrentSelection(null); - } else { - setCurrentSelection({ - start: selection.start, - end: selection.end - }); - setStart(selection.start); - setEnd(selection.end); - } - } - return; - - case "addAnnotation": - // Start annotation creation flow - handleAddAnnotation(message.data.start, message.data.end); - return; - - case "removeAnnotation": - // Remove selected annotation - handleRemoveAnnotation(); - return; - - case "setAnnotationColor": - // Set color for selected annotation - handleSetAnnotationColor(message.data.color); - return; - - case "chooseAnnotationType": - // Choose annotation type - handleChooseAnnType(message.data.start, message.data.end, message.data.documentContent); - return; - } - }; - - window.addEventListener("message", handleMessage); - return () => { - window.removeEventListener("message", handleMessage); - }; - }, [documentUri]); + // Check if any annotations need to be retagged + const needsRetag = annotations.some(annotation => + isAnnotationOutOfSync(annotation, documentText) + ); + setShowRetagBanner(needsRetag); + }, [annotations, documentText]); - // Find the selected annotation based on the character position - useEffect(() => { - if (charNum !== undefined) { - const annotation = annotations.find( - (annotation) => annotation.start <= charNum && annotation.end >= charNum - ); - if (annotation) { - // Set the selected annotation id - vscode.postMessage({ - command: "setSelectedAnnotationId", - data: { - annotationId: annotation.id - } - }); - setSelectedAnnotationId(annotation.id); - } - } - }, [charNum, annotations]); + // ... rest of the existing code ... - if (!chooseAnnotationType) { - return ( -
- {hasSelection && ( - - )} - - {showRetagBanner && ( - - )} - - + {showRetagBanner && } + {isAdding && ( + - - {!hasSelection && ( -

To add more annotations, highlight text in the editor and choose a note type.

- )} -
- ); - } else { - return ( -
-
-
Choose Annotation Type
-
- - - -
-
- + )} + {annotations.length === 0 ? ( +
No annotations found
+ ) : ( -
- ); - } + )} +
+ ); } export default App; \ No newline at end of file