diff --git a/.eslintrc.json b/.eslintrc.json index a4f4c43..b4df106 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -16,7 +16,7 @@ "rules": { "no-const-assign": "warn", "no-this-before-super": "warn", - "no-undef": "warn", + "no-undef": "off", "no-unreachable": "warn", "no-unused-vars": "off", "constructor-super": "warn", diff --git a/.gitignore b/.gitignore index d7802a3..ca86ef1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -node_modules +/node_modules/ /package-lock.json /.vscode-test/ -/build/ \ No newline at end of file +/build/ +/.DS_Store \ No newline at end of file diff --git a/.vscodeignore b/.vscodeignore index a5b7de8..cd8d85e 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -1,10 +1,15 @@ +# FOLDERS .vscode/** .vscode-test/** test/** -.gitignore -.yarnrc -vsc-extension-quickstart.md +node_modules **/jsconfig.json **/*.map **/.eslintrc.json + +# FILES +.gitignore +.yarnrc +vsc-extension-quickstart.md **/*.js.map + diff --git a/package-lock.json b/package-lock.json index ca3fbe1..47a3f1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@babel/core": "^7.23.3", - "@babel/parser": "^7.23.4", + "@babel/parser": "^7.23.9", "@babel/preset-env": "^7.23.3", "@babel/preset-react": "^7.23.3", "babel": "^6.23.0", @@ -104,20 +104,20 @@ } }, "node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -184,9 +184,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", - "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", + "version": "7.23.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", + "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.20", @@ -429,13 +429,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", - "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -794,9 +794,9 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", - "integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5", @@ -1130,9 +1130,9 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", - "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-module-transforms": "^7.23.3", @@ -1583,9 +1583,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz", - "integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-compilation-targets": "^7.23.6", @@ -1614,7 +1614,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.7", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", "@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoping": "^7.23.4", @@ -1636,7 +1636,7 @@ "@babel/plugin-transform-member-expression-literals": "^7.23.3", "@babel/plugin-transform-modules-amd": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", "@babel/plugin-transform-modules-umd": "^7.23.3", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.23.3", @@ -1662,9 +1662,9 @@ "@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -1732,9 +1732,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1743,22 +1743,22 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", @@ -1766,8 +1766,8 @@ "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1776,9 +1776,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -3735,11 +3735,11 @@ } }, "node_modules/@reactflow/background": { - "version": "11.3.7", - "resolved": "https://registry.npmjs.org/@reactflow/background/-/background-11.3.7.tgz", - "integrity": "sha512-PhkvoFtO/NXJgFtBvfbPwdR/6/dl25egQlFhKWS3T4aYa7rh80dvf6dF3t6+JXJS4q5ToYJizD2/n8/qylo1yQ==", + "version": "11.3.8", + "resolved": "https://registry.npmjs.org/@reactflow/background/-/background-11.3.8.tgz", + "integrity": "sha512-U4aI54F7PwqgYI0Knv72QFRI/wXeipPmIYAlDsA0j51+tlPxs3Nk2z7G1/4pC11GxEZkgQVfcIXro4l1Fk+bIQ==", "dependencies": { - "@reactflow/core": "11.10.2", + "@reactflow/core": "11.10.3", "classcat": "^5.0.3", "zustand": "^4.4.1" }, @@ -3749,11 +3749,11 @@ } }, "node_modules/@reactflow/controls": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/@reactflow/controls/-/controls-11.2.7.tgz", - "integrity": "sha512-mugzVALH/SuKlVKk+JCRm1OXQ+p8e9+k8PCTIaqL+nBl+lPF8KA4uMm8ApsOvhuSAb2A80ezewpyvYHr0qSYVA==", + "version": "11.2.8", + "resolved": "https://registry.npmjs.org/@reactflow/controls/-/controls-11.2.8.tgz", + "integrity": "sha512-Y9YVx38sRjYtbPsI/xa+B1FGN73FV1GqqajlmGfrc1TmqhJaX+gaMXMvVazT/N5haK1hMJvOApUTLQ2V/5Rdbg==", "dependencies": { - "@reactflow/core": "11.10.2", + "@reactflow/core": "11.10.3", "classcat": "^5.0.3", "zustand": "^4.4.1" }, @@ -3763,9 +3763,9 @@ } }, "node_modules/@reactflow/core": { - "version": "11.10.2", - "resolved": "https://registry.npmjs.org/@reactflow/core/-/core-11.10.2.tgz", - "integrity": "sha512-/cbTxtFpfkIGReSVkcnQhS4Jx4VFY2AhPlJ5n0sbPtnR7OWowF9zodh5Yyzr4j1NOUoBgJ9h+UqGEwwY2dbAlw==", + "version": "11.10.3", + "resolved": "https://registry.npmjs.org/@reactflow/core/-/core-11.10.3.tgz", + "integrity": "sha512-nV3nep4fjBy3h8mYSnJcclGcQtj8fkUBmNkEwCZCK4ps+n3HNkXFB0BRisSnQz6GRQlYboSsi0cThEl3KdNITw==", "dependencies": { "@types/d3": "^7.4.0", "@types/d3-drag": "^3.0.1", @@ -3783,11 +3783,11 @@ } }, "node_modules/@reactflow/minimap": { - "version": "11.7.7", - "resolved": "https://registry.npmjs.org/@reactflow/minimap/-/minimap-11.7.7.tgz", - "integrity": "sha512-Pwqw31tJ663cJur6ypqyJU33nPckvTepmz96erdQZoHsfOyLmFj4nXT7afC30DJ48lp0nfNsw+028mlf7f/h4g==", + "version": "11.7.8", + "resolved": "https://registry.npmjs.org/@reactflow/minimap/-/minimap-11.7.8.tgz", + "integrity": "sha512-MwyP5q3VomC91Dhd4P6YcxEfnjDbREGYV6rRxbSJSTHiG0x7ETQCcPelYDGy7JvQej77Pa2yJ4g0FDwP7CsQEA==", "dependencies": { - "@reactflow/core": "11.10.2", + "@reactflow/core": "11.10.3", "@types/d3-selection": "^3.0.3", "@types/d3-zoom": "^3.0.1", "classcat": "^5.0.3", @@ -3801,11 +3801,11 @@ } }, "node_modules/@reactflow/node-resizer": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/@reactflow/node-resizer/-/node-resizer-2.2.7.tgz", - "integrity": "sha512-BMBstmWNiklHnnAjHu8irkiPQ8/k8nnjzqlTql4acbVhD6Tsdxx/t/saOkELmfQODqGZNiPw9+pHcAHgtE6oNQ==", + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@reactflow/node-resizer/-/node-resizer-2.2.8.tgz", + "integrity": "sha512-u/EXLpvOfAmq1sGoPYwoX4gi0PnCi0mH3eHVClHNc8JQD0WCqcV1UeVV7H3PF+1SGhhg/aOv/vPG1PcQ5fu4jQ==", "dependencies": { - "@reactflow/core": "11.10.2", + "@reactflow/core": "11.10.3", "classcat": "^5.0.4", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", @@ -3817,11 +3817,11 @@ } }, "node_modules/@reactflow/node-toolbar": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@reactflow/node-toolbar/-/node-toolbar-1.3.7.tgz", - "integrity": "sha512-75moEQKg23YKA3A2DNSFhq719ZPmby5mpwOD+NO7ZffJ88oMS/2eY8l8qpA3hvb1PTBHDxyKazhJirW+f4t0Wg==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@reactflow/node-toolbar/-/node-toolbar-1.3.8.tgz", + "integrity": "sha512-cfvlTPeJa/ciQTosx2bGrjHT8K/UL9kznpvpOzeZFnJm5UQXmbwAYt4Vo6GfkD51mORcIL7ujQJvB9ym3ZI9KA==", "dependencies": { - "@reactflow/core": "11.10.2", + "@reactflow/core": "11.10.3", "classcat": "^5.0.3", "zustand": "^4.4.1" }, @@ -4150,9 +4150,9 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/geojson": { - "version": "7946.0.13", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", - "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==" + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" }, "node_modules/@types/glob": { "version": "8.1.0", @@ -4198,9 +4198,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.11", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.11.tgz", - "integrity": "sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==", + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -4225,9 +4225,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.8.tgz", - "integrity": "sha512-g1pZtPhsvGVTwmeVoexWZLTQaOvXwoSq//pTL0DHeNzUDrFnir4fgETdhjhIxjVnN+hKOuh98+E1eMLnUXstFg==", + "version": "18.19.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.14.tgz", + "integrity": "sha512-EnQ4Us2rmOS64nHDWr0XqAD8DsO6f3XR6lf9UIIrZQpUzPVdN/oPuEzfDWNHSyXLvoGgjuEm/sPwFGSSs35Wtg==", "dependencies": { "undici-types": "~5.26.4" } @@ -4239,9 +4239,9 @@ "devOptional": true }, "node_modules/@types/react": { - "version": "18.2.48", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz", - "integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==", + "version": "18.2.52", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.52.tgz", + "integrity": "sha512-E/YjWh3tH+qsLKaUzgpZb5AY0ChVa+ZJzF7ogehVILrFpdQk6nC/WXOv0bfFEABbXbgNxLBGU7IIZByPKb6eBw==", "devOptional": true, "dependencies": { "@types/prop-types": "*", @@ -4271,9 +4271,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.85.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.85.0.tgz", - "integrity": "sha512-CF/RBon/GXwdfmnjZj0WTUMZN5H6YITOfBCP4iEZlOtVQXuzw6t7Le7+cR+7JzdMrnlm7Mfp49Oj2TuSXIWo3g==", + "version": "1.86.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.86.0.tgz", + "integrity": "sha512-DnIXf2ftWv+9LWOB5OJeIeaLigLHF7fdXF6atfc7X5g2w/wVZBgk0amP7b+ub5xAuW1q7qP5YcFvOcit/DtyCQ==", "dev": true }, "node_modules/@types/yargs": { @@ -4316,9 +4316,9 @@ } }, "node_modules/@vscode/test-electron": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz", - "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==", + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.9.tgz", + "integrity": "sha512-z3eiChaCQXMqBnk2aHHSEkobmC2VRalFQN0ApOAtydL172zXGxTwGrRtviT5HnUB+Q+G3vtEYFtuQkYqBzYgMA==", "dev": true, "dependencies": { "http-proxy-agent": "^4.0.1", @@ -4929,27 +4929,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", - "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", - "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -5047,9 +5032,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", + "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", "funding": [ { "type": "opencollective", @@ -5065,8 +5050,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", + "caniuse-lite": "^1.0.30001580", + "electron-to-chromium": "^1.4.648", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -5131,9 +5116,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001579", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", - "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "version": "1.0.30001583", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001583.tgz", + "integrity": "sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q==", "funding": [ { "type": "opencollective", @@ -5601,9 +5586,9 @@ } }, "node_modules/css-loader": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.9.1.tgz", - "integrity": "sha512-OzABOh0+26JKFdMzlK6PY1u5Zx8+Ck7CVRlcGNZoY9qwJjdfu2VWFuprTIpPW+Av5TZTVViYWcFQaEEQURLknQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", @@ -5622,7 +5607,16 @@ "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/css-loader/node_modules/lru-cache": { @@ -6138,11 +6132,11 @@ } }, "node_modules/delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", "dependencies": { - "robust-predicates": "^3.0.0" + "robust-predicates": "^3.0.2" } }, "node_modules/detect-newline": { @@ -6203,9 +6197,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.643", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.643.tgz", - "integrity": "sha512-QHscvvS7gt155PtoRC0dR2ilhL8E9LHhfTQEq1uD5AL0524rBLAwpAREFH06f87/e45B9XkR6Ki5dbhbCsVEIg==" + "version": "1.4.656", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.656.tgz", + "integrity": "sha512-9AQB5eFTHyR3Gvt2t/NwR0le2jBSUNwCnMbUCejFWHD+so4tH40/dRLgoE+jxlPeWS43XJewyvCv+I8LPMl49Q==" }, "node_modules/emittery": { "version": "0.13.1", @@ -6238,9 +6232,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", - "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", + "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", "dev": true, "bin": { "envinfo": "dist/cli.js" @@ -6669,9 +6663,9 @@ } }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", + "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -7015,9 +7009,9 @@ } }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -9897,9 +9891,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -11094,16 +11088,16 @@ "dev": true }, "node_modules/reactflow": { - "version": "11.10.2", - "resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.10.2.tgz", - "integrity": "sha512-tqQJfPEiIkXonT3piVYf+F9CvABI5e28t5I6rpaLTnO8YVCAOh1h0f+ziDKz0Bx9Y2B/mFgyz+H7LZeUp/+lhQ==", + "version": "11.10.3", + "resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.10.3.tgz", + "integrity": "sha512-DGNrTdkWjZtPOhj5MV8fiWWGkJo+otMVdoJ9l67bQL+Xf+8NkJ4AHmRXoYIxtgcENzwTr5WTAIJlswV9i91cyw==", "dependencies": { - "@reactflow/background": "11.3.7", - "@reactflow/controls": "11.2.7", - "@reactflow/core": "11.10.2", - "@reactflow/minimap": "11.7.7", - "@reactflow/node-resizer": "2.2.7", - "@reactflow/node-toolbar": "1.3.7" + "@reactflow/background": "11.3.8", + "@reactflow/controls": "11.2.8", + "@reactflow/core": "11.10.3", + "@reactflow/minimap": "11.7.8", + "@reactflow/node-resizer": "2.2.8", + "@reactflow/node-toolbar": "1.3.8" }, "peerDependencies": { "react": ">=17", @@ -12501,18 +12495,18 @@ } }, "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "version": "5.90.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz", + "integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==", "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", + "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.11.5", "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", @@ -12526,7 +12520,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, diff --git a/package.json b/package.json index e5e4fa1..83de3b9 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,17 @@ { "name": "react-labyrinth", "displayName": "React Labyrinth", - "description": "React Server Components visualization tool", + "description": "React Component Type hierarchy tree visualization tool", "version": "0.0.1", + "icon": "./media/reactLbayrinthFinal.png", "publisher": "ReactLabyrinthDev", + "preview": false, "engines": { "vscode": "^1.85.1" }, "repository": { "type": "git", - "url": "https://github.com/oslabs-beta/React-Labyrinth" + "url": "https://github.com/oslabs-beta/React-Labyrinth/tree/main" }, "categories": [ "Other" @@ -17,14 +19,18 @@ "keywords": [ "react", "rsc", + "react components", "hierarchy tree", "parent-child", "visualizer", - "server component" + "server component", + "client component" ], "license": "MIT", "pricing": "Free", - "activationEvents": [], + "activationEvents": [ + "onStartupFinished" + ], "main": "./build/extension.js", "contributes": { "commands": [ @@ -51,28 +57,25 @@ "views": { "react-labyrinth": [ { - "id": "metrics-file", - "name": "Metrics" - }, - { - "id": "test", - "name": "Test" + "id": "tree-render", + "name": "Tree" } ] }, "viewsWelcome": [ { - "view": "metrics-file", - "contents": "View tree to see where improvements can be made!\n[View Tree](command:myExtension.pickFile)\n" + "view": "tree-render", + "contents": "View tree to see component types!\n[View Tree](command:myExtension.pickFile)\n" } ] }, "scripts": { + "vscode:prepublish": "prod", "lint": "eslint .", "pretest": "npm run lint", "test": "npx tsc ; node ./build/src/test/runTest.js", - "dev": "webpack --watch", - "webpack": "webpack" + "dev": "webpack --mode development --config webpack.config.ts --watch", + "prod": "webpack --mode production --config webpack.config.ts" }, "devDependencies": { "@babel/preset-typescript": "^7.23.3", @@ -97,7 +100,7 @@ }, "dependencies": { "@babel/core": "^7.23.3", - "@babel/parser": "^7.23.4", + "@babel/parser": "^7.23.9", "@babel/preset-env": "^7.23.3", "@babel/preset-react": "^7.23.3", "babel": "^6.23.0", diff --git a/src/extension.ts b/src/extension.ts index 8b01c00..0022e27 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import {createPanel} from './panel'; import { Parser } from './parser'; import { Tree } from './types/tree'; +import { showNotification } from './utils/modal'; let tree: Parser | undefined = undefined; let panel: vscode.WebviewPanel | undefined = undefined; @@ -27,7 +28,7 @@ function activate(context: vscode.ExtensionContext) { // Throw error message if no file was selected if (!fileArray || fileArray.length === 0) { - vscode.window.showErrorMessage('No file selected'); + showNotification({message: 'No file selected'}); return; } diff --git a/src/parser.ts b/src/parser.ts index f3c0865..bb1b2b6 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -49,7 +49,7 @@ export class Parser { reactRouter: false, reduxConnect: false, children: [], - parent: null, + parent: '', parentList: [], props: {}, error: '', @@ -80,7 +80,7 @@ export class Parser { }; public getTree(): Tree { - return this.tree; + return this.tree!; } // Set entryFile property with the result of Parser (from workspace state) @@ -178,9 +178,6 @@ export class Parser { if (componentTree.parentList.includes(componentTree.filePath)) { return; } - // if (typeof componentTree.parentList === 'string' && componentTree.parentList.includes(componentTree.filePath)) { - // return; - // } // Create abstract syntax tree of current component tree file let ast: babel.ParseResult; @@ -289,7 +286,7 @@ export class Parser { } // Determines server or client component type (looks for use of 'use client' and react/redux state hooks) - private getComponentType(directive: { [key: string]: any }[], body: { [key: string]: any }[]): boolean { + private getComponentType(directive: { [key: string]: any }[], body: { [key: string]: any }[]) { const defaultErr = (err) => { return { method: 'Error in getCallee method of Parser:', @@ -297,7 +294,6 @@ export class Parser { } }; - // console.log('directive: ', directive); // Initial check for use of directives (ex: 'use client', 'use server', 'use strict') // Accounts for more than one directive for (let i = 0; i < directive.length; i++) { @@ -310,8 +306,14 @@ export class Parser { } // Second check for use of React/Redux hooks + // Checks for components declared using 'const' const bodyCallee = body.filter((item) => item.type === 'VariableDeclaration'); - if (bodyCallee.length === 0) return false; + + // Checks for components declared using 'export default function' + const exportCallee = body.filter((item) => item.type === 'ExportDefaultDeclaration'); + + // Checks for components declared using 'function' + const functionCallee = body.filter((item) => item.type === 'FunctionDeclaration'); // Helper function const calleeHelper = (item) => { @@ -333,6 +335,8 @@ export class Parser { useDispatch: 0, useActions: 0, useSelector: 0, + useShallowEqualSelector: 0, + useStore: 0, bindActionCreators: 0, } if (item.type === 'VariableDeclaration') { @@ -363,39 +367,43 @@ export class Parser { return false; } - if (bodyCallee.length === 1) { - const calleeArr = bodyCallee[0].declarations[0]?.init?.body?.body; - if (calleeArr === undefined) return false; + // Process Function Declarations + for (const func of functionCallee) { + const calleeArr = func.body?.body; + if (!calleeArr) continue; // Skip if no body - let checkTrue = false; - for (let i = 0; i < calleeArr.length; i++) { - if (checkTrue) return true; - checkTrue = calleeHelper(calleeArr[i]); + for (const callee of calleeArr) { + if (calleeHelper(callee)) { + return true; + } } - return checkTrue; } - else if (bodyCallee.length > 1) { - let calleeArr: []; - for (let i = 0; i < bodyCallee.length; i++) { - try { - if (bodyCallee[i].declarations[0]?.init?.body?.body) { - calleeArr = bodyCallee[i].declarations[0].init.body.body; - } - } - catch (err) { - const error = defaultErr(err); - console.error(error.method, '\n', error.log); + + // Process Export Declarations + for (const exportDecl of exportCallee) { + const calleeArr = exportDecl.declaration.body?.body; + if (!calleeArr) continue; // Skip if no body + + for (const callee of calleeArr) { + if (calleeHelper(callee)) { + return true; } } - - if (calleeArr === undefined) return false; - let checkTrue = false; - for (let i = 0; i < calleeArr.length; i++) { - if (checkTrue) return true; - checkTrue = calleeHelper(calleeArr[i]); + } + + // Process Body Declarations + for (const bodyDecl of bodyCallee) { + const calleeArr = bodyDecl.declarations[0]?.init?.body?.body; + if (!calleeArr) continue; // Skip if no body + + for (const callee of calleeArr) { + if (calleeHelper(callee)) { + return true; + } } - return checkTrue; } + + return false; } // Finds JSX React Components in current file diff --git a/src/test/runTest.ts b/src/test/runTest.ts index 6e7ebf1..7b88da4 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -2,7 +2,6 @@ import * as path from 'path'; import { runTests } from '@vscode/test-electron'; async function main() { - console.log('made it through the line before try block'); try { // The folder containing the Extension Manifest package.json // Passed to `--extensionDevelopmentPath` @@ -12,8 +11,6 @@ async function main() { // Passed to --extensionTestsPath const extensionTestsPath = path.resolve(__dirname, './suite/index'); - console.log('inside try block after var declarations'); - // Download VS Code, unzip it and run the integration test await runTests({ version: "1.85.1", diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index c578dab..d7f4f3f 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -4,8 +4,6 @@ import * as jest from 'jest'; export async function run(): Promise { try { - console.log('inside try block of index.ts'); - const testsRoot = path.resolve(__dirname, '..'); const files = await glob('**/**.test.js', { cwd: testsRoot }); @@ -14,15 +12,10 @@ export async function run(): Promise { return; } - console.log('test files: ', files); - return new Promise(async (c, e) => { try { - console.log('inside promise block of index.ts before await ') await jest.run([...files]); - console.log('inside promise block of index.ts after await') c(); - console.log('inside promise block of index.ts after c()') } catch (err) { console.error(err); e(err); diff --git a/src/test/suite/parser.test.ts b/src/test/suite/parser.test.ts index 23d6181..ecc3210 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -1,79 +1,159 @@ import { Parser } from '../../parser'; import * as path from 'path'; -import { beforeEach, expect, test } from '@jest/globals'; - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -import * as vscode from 'vscode' -// const myExtension = require('../extension'); +import { beforeAll, beforeEach, expect, test } from '@jest/globals'; describe('Parser Test Suite', () => { let parser, tree, file; const fs = require('fs'); - - // UNPARSED TREE TEST - xdescribe('It initializes correctly', () => { + // TEST 6: BAD IMPORT OF APP2 FROM APP1 COMPONENT + describe('Catches bad imports', () => { beforeEach(() => { - // Assign the test file and make new instance of Parser - file = path.join(__dirname, '../test_cases/tc_0/index.js'); - // file = path.join(__dirname, '../../../src/test/test_apps/test_0/index.js'); + file = path.join(__dirname, '../../../../src/test/test_cases/tc_6/component/App.jsx'); parser = new Parser(file); + tree = parser.parse(); }); - - test('It instantiates an object for the parser class', () => { - expect((parser)).toBeInstanceOf(Parser); + + test("Child component with bad file path does not show up on the node tree", () => { + expect(tree.children.length).toBe(0); }); - - test('It begins with a suitable entry file and a tree that is not yet defined', () => { - expect(parser.entryFile).toEqual(file); - expect(tree).toBeUndefined(); + }); + + // TEST 7: SYNTAX ERROR IN APP FILE CAUSES PARSER ERROR + describe('Parser should not work for components with syntax errors in the code', () => { + beforeEach(() => { + file = path.join(__dirname, '../../../../src/test/test_cases/tc_7/index.js'); + parser = new Parser(file); + tree = parser.parse(); + }); + + test("Parser stops parsing when there is a syntax error in a component", () => { + expect(tree.children.length).toBe(0); }); }); - // TEST 0: ONE CHILD - xdescribe('It works for simple apps', () => { - beforeEach(() => { - file = path.join(__dirname, ''); + // TEST 11: PARSER DOESN'T BREAK UPON RECURSIVE COMPONENTS + describe('It should render the second call of mutually recursive components, but no further', () => { + beforeAll(() => { + file = path.join(__dirname, '../../../../src/test/test_cases/tc_11/index.js'); parser = new Parser(file); tree = parser.parse(); }); - test('It returns an defined object tree when parsed', () => { + test('Tree should not be undefined', () => { expect(tree).toBeDefined(); - //expect(tree).toMatchObject() }); - // test('Parsed tree has a property called name with value index and one child with name App', () => { + test('Tree should have an index component while child App1, grandchild App2, great-grandchild App1', () => { + expect(tree).toHaveProperty('name', 'index'); + expect(tree.children).toHaveLength(1); + expect(tree.children[0]).toHaveProperty('name', 'App1'); + expect(tree.children[0].children).toHaveLength(1); + expect(tree.children[0].children[0]).toHaveProperty('name', 'App2'); + expect(tree.children[0].children[0].children).toHaveLength(1); + expect(tree.children[0].children[0].children[0]).toHaveProperty('name', 'App1'); + expect(tree.children[0].children[0].children[0].children).toHaveLength(0); + }); + }); - // }); + // TEST 12A: NEXT.JS APPS (PAGES ROUTER) + describe('It should parse Next.js applications using Pages Router', () => { + beforeAll(() => { + file = path.join(__dirname, '../../../../src/test/test_cases/tc_12a/pages/index.js'); + parser = new Parser(file); + tree = parser.parse(); + }); + + test('Root should be named index, children should be named Head and Navbar, children of Navbar should be named Link and Image', () => { + expect(tree).toHaveProperty('name', 'index'); + expect(tree.children).toHaveLength(2); + expect(tree.children[0]).toHaveProperty('name', 'Head'); + expect(tree.children[1]).toHaveProperty('name', 'Navbar'); + + expect(tree.children[1].children).toHaveLength(2); + expect(tree.children[1].children[0]).toHaveProperty('name', 'Link'); + expect(tree.children[1].children[1]).toHaveProperty('name', 'Image'); + }); }); - // TEST 6: BAD IMPORT OF APP2 FROM APP1 COMPONENT - describe('Catches bad imports', () => { - beforeEach(() => { - file = path.join(__dirname, '../../../../src/test/test_cases/tc_6/component/App.jsx'); + // TEST 12B: NEXT.JS APPS (APP ROUTER) + describe('It should parser Next.js applications using Apps Router', () => { + beforeAll(() => { + file = path.join(__dirname, '../../../../src/test/test_cases/tc_12b/app/page.jsx'); parser = new Parser(file); tree = parser.parse(); }); - test("Child component with bad file path does not show up on the node tree", () => { - expect(tree.children.length).toBe(0); - }) - }) + test('Root should be named page, it should have one child named Homepage', () => { + expect(tree).toHaveProperty('name', 'page'); + expect(tree.children).toHaveLength(1); + expect(tree.children[0]).toHaveProperty('name', 'HomePage'); + }); + }); + + // TEST 13: VARIABLE DECLARATION IMPORTS AND REACT.LAZY IMPORTS + describe('It should parse VariableDeclaration imports including React.lazy imports', () => { + beforeAll(() => { + file = path.join(__dirname, '../../../../src/test/test_cases/tc_13/index.js'); + parser = new Parser(file); + tree = parser.parse(); + }); - // TEST 7: SYNTAX ERROR IN APP FILE CAUSES PARSER ERROR - describe('Parser should not work for components with syntax errors in the code', () => { - beforeEach(() => { - file = path.join(__dirname, '../../../../src/test/test_cases/tc_7/index.js'); + test('Root should be named index, it should have one child named App', () => { + expect(tree).toHaveProperty('name', 'index'); + expect(tree.children).toHaveLength(1); + expect(tree.children[0]).toHaveProperty('name', 'App'); + }); + + test('App should have three children, Component1, Component2 and Component3, all found successfully', () => { + expect(tree.children[0].children[0]).toHaveProperty('name', 'Component1'); + expect(tree.children[0].children[0]).toHaveProperty('thirdParty', false); + + expect(tree.children[0].children[1]).toHaveProperty('name', 'Component2'); + expect(tree.children[0].children[1]).toHaveProperty('thirdParty', false); + + expect(tree.children[0].children[2]).toHaveProperty('name', 'Component3'); + expect(tree.children[0].children[2]).toHaveProperty('thirdParty', false); + }); + }); + + // TEST 14: CHECK IF COMPONENT IS A CLIENT COMPONENT USING HOOKS AND DIRECTIVES + describe('It should parse components and determine if the component type', () => { + beforeAll(() => { + file = path.join(__dirname, '../../../../src/test/test_cases/tc_14/index.js'); parser = new Parser(file); tree = parser.parse(); }); - - test("Parser stops parsing when there is a syntax error in a component", () => { - expect(tree.children.length).toBe(0); + + test('Root should be named index, it should have one children named App', () => { + expect(tree).toHaveProperty('name', 'index'); + expect(tree.children).toHaveLength(1); + expect(tree.children[0]).toHaveProperty('name', 'App'); }); - }) + + test('App should have three children, Component1, Component4, Component5 is a client component using hooks, Component2 is a client component using directives, and Component3, Component6, Component7 is not a client component', () => { + expect(tree.children[0].children[0]).toHaveProperty('name', 'Component1'); + expect(tree.children[0].children[0]).toHaveProperty('isClientComponent', true); + + expect(tree.children[0].children[1]).toHaveProperty('name', 'Component2'); + expect(tree.children[0].children[1]).toHaveProperty('isClientComponent', true); + + expect(tree.children[0].children[2]).toHaveProperty('name', 'Component3'); + expect(tree.children[0].children[2]).toHaveProperty('isClientComponent', false); + + expect(tree.children[0].children[3]).toHaveProperty('name', 'Component4'); + expect(tree.children[0].children[3]).toHaveProperty('isClientComponent', true); + + expect(tree.children[0].children[4]).toHaveProperty('name', 'Component5'); + expect(tree.children[0].children[4]).toHaveProperty('isClientComponent', true); + + expect(tree.children[0].children[5]).toHaveProperty('name', 'Component6'); + expect(tree.children[0].children[5]).toHaveProperty('isClientComponent', false); + + expect(tree.children[0].children[6]).toHaveProperty('name', 'Component7'); + expect(tree.children[0].children[6]).toHaveProperty('isClientComponent', false); + }); + }); // these are the 14 tests we need to test for @@ -93,4 +173,5 @@ describe('Parser Test Suite', () => { // TEST 14: CHECK IF COMPONENT IS CLIENT OR SERVER (USING HOOKS & DIRECTIVES) => BOOLEAN (priority) // LOU is doing EXTENSION TEST in extension.test.ts + }); diff --git a/src/test/test_cases/tc_11/components/App1.jsx b/src/test/test_cases/tc_11/components/App1.jsx new file mode 100644 index 0000000..0e4eb73 --- /dev/null +++ b/src/test/test_cases/tc_11/components/App1.jsx @@ -0,0 +1,10 @@ +import App2 from './App2.jsx'; + +export default function App1() { + return ( +
+
I am App 1
+ +
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_11/components/App2.jsx b/src/test/test_cases/tc_11/components/App2.jsx new file mode 100644 index 0000000..e278e11 --- /dev/null +++ b/src/test/test_cases/tc_11/components/App2.jsx @@ -0,0 +1,10 @@ +import App1 from './App1.jsx'; + +export default function App2() { + return ( +
+
This is App 2
+ +
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_11/index.js b/src/test/test_cases/tc_11/index.js new file mode 100644 index 0000000..442983d --- /dev/null +++ b/src/test/test_cases/tc_11/index.js @@ -0,0 +1,8 @@ +// Test Case 11 - Recursive import of App1 and App2 + +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App1 from './components/App1.jsx'; + +const root = createRoot(document.getElementById('root')); +root.render(); \ No newline at end of file diff --git a/src/test/test_cases/tc_12a/components/Navbar.jsx b/src/test/test_cases/tc_12a/components/Navbar.jsx new file mode 100644 index 0000000..38fcb5c --- /dev/null +++ b/src/test/test_cases/tc_12a/components/Navbar.jsx @@ -0,0 +1,31 @@ +import Link from 'next/link'; +import Image from 'next/image'; +import logo from '../public/nextjs_logo.png'; + +export const Navbar = () => { + return ( + + ); +}; + diff --git a/src/test/test_cases/tc_12a/pages/index.js b/src/test/test_cases/tc_12a/pages/index.js new file mode 100644 index 0000000..4a09f1d --- /dev/null +++ b/src/test/test_cases/tc_12a/pages/index.js @@ -0,0 +1,24 @@ +// Test Case 12a - Parse for Next.js using Pages Router + +import Head from 'next/head'; +import Navbar from '../components/Navbar.jsx'; + +export default function Home() { + return ( +
+ + Home Page + + + + +
+

Welcome to Next.js!

+

This is a sample index page created with Next.js.

+
+
+

Footer content here

+
+
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_12b/app/homepage.jsx b/src/test/test_cases/tc_12b/app/homepage.jsx new file mode 100644 index 0000000..f83e44e --- /dev/null +++ b/src/test/test_cases/tc_12b/app/homepage.jsx @@ -0,0 +1,11 @@ +'use client' + +export default function HomePage({ recentPosts }) { + return ( +
+ {recentPosts.map((post) => ( +
{post.title}
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_12b/app/layout.jsx b/src/test/test_cases/tc_12b/app/layout.jsx new file mode 100644 index 0000000..46806c3 --- /dev/null +++ b/src/test/test_cases/tc_12b/app/layout.jsx @@ -0,0 +1,15 @@ +import './styles/globals.css'; +import React from 'react'; + +export const metadata = { + title: 'Home', + description: 'Welcome to Next.js', +} + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_12b/app/page.jsx b/src/test/test_cases/tc_12b/app/page.jsx new file mode 100644 index 0000000..5f5a9df --- /dev/null +++ b/src/test/test_cases/tc_12b/app/page.jsx @@ -0,0 +1,17 @@ +// Import your Client Component +import HomePage from './homepage.jsx'; + +async function getPosts() { + const res = await fetch('https://...'); + const posts = await res.json(); + return posts; +} + +export default async function Page() { + // Fetch data directly in a Server Component + const recentPosts = await getPosts(); + // Forward fetched data to your Client Component + return ( + + ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_13/components/App.jsx b/src/test/test_cases/tc_13/components/App.jsx new file mode 100644 index 0000000..c2ed47d --- /dev/null +++ b/src/test/test_cases/tc_13/components/App.jsx @@ -0,0 +1,14 @@ +import { lazy } from "react"; +const Component1 = lazy(() => import('./Component1')); +import Component2 from "./Component2"; +import Component3 from "./Component3"; + +export default function Pages() { + return ( +
+ + + +
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_13/components/Component1.jsx b/src/test/test_cases/tc_13/components/Component1.jsx new file mode 100644 index 0000000..d1a4385 --- /dev/null +++ b/src/test/test_cases/tc_13/components/Component1.jsx @@ -0,0 +1,7 @@ +export default function Component1() { + return ( +
+
This is Component 1.
+
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_13/components/Component2.jsx b/src/test/test_cases/tc_13/components/Component2.jsx new file mode 100644 index 0000000..cc37f57 --- /dev/null +++ b/src/test/test_cases/tc_13/components/Component2.jsx @@ -0,0 +1,7 @@ +export default function Component2() { + return ( +
+
This is Component 2.
+
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_13/components/Component3.jsx b/src/test/test_cases/tc_13/components/Component3.jsx new file mode 100644 index 0000000..1bf40a6 --- /dev/null +++ b/src/test/test_cases/tc_13/components/Component3.jsx @@ -0,0 +1,7 @@ +export default function Component3() { + return ( +
+
This is Component 3.
+
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_13/index.js b/src/test/test_cases/tc_13/index.js new file mode 100644 index 0000000..3b69d18 --- /dev/null +++ b/src/test/test_cases/tc_13/index.js @@ -0,0 +1,8 @@ +// Test Case 13 - Recursive import of App1 and App2 + +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './components/App'; + +const root = createRoot(document.getElementById('root')); +root.render(); \ No newline at end of file diff --git a/src/test/test_cases/tc_14/components/App.jsx b/src/test/test_cases/tc_14/components/App.jsx new file mode 100644 index 0000000..5b5642d --- /dev/null +++ b/src/test/test_cases/tc_14/components/App.jsx @@ -0,0 +1,22 @@ +import React from "react"; +import Component1 from "./Component1"; +import Component2 from "./Component2"; +import Component3 from "./Component3"; +import Component4 from "./Component4"; +import Component5 from "./Component5"; +import Component6 from "./Component6"; +import Component7 from "./Component7"; + +export default function Pages() { + return ( +
+ + + + + + + +
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_14/components/Component1.jsx b/src/test/test_cases/tc_14/components/Component1.jsx new file mode 100644 index 0000000..6c7745b --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component1.jsx @@ -0,0 +1,19 @@ +import { useState } from 'react'; + +const Component1 = () => { + const [count, setCount] = useState(0); + + const handleClick = () => { + setCount(count + 1); + }; + + return ( +
+

This is Component 1.

+

Count: {count}

+ ; +
+ ); +} + +export default Component1; \ No newline at end of file diff --git a/src/test/test_cases/tc_14/components/Component2.jsx b/src/test/test_cases/tc_14/components/Component2.jsx new file mode 100644 index 0000000..6a3ffaa --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component2.jsx @@ -0,0 +1,21 @@ +'use client' +import { useState, useEffect } from 'react'; + +export default function Component2() { + const [seconds, setSeconds] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setSeconds(prevSeconds => prevSeconds + 1); + }, 1000); + + return () => clearInterval(interval); + }); + + return ( +
+

Timer Component

+

Seconds: {seconds}

+
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_14/components/Component3.jsx b/src/test/test_cases/tc_14/components/Component3.jsx new file mode 100644 index 0000000..bc25f68 --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component3.jsx @@ -0,0 +1,8 @@ +export default function Component3() { + return ( +
+

Static Component

+

This is a static component without interactivity or state.

+
+ ); +} \ No newline at end of file diff --git a/src/test/test_cases/tc_14/components/Component4.jsx b/src/test/test_cases/tc_14/components/Component4.jsx new file mode 100644 index 0000000..21498d5 --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component4.jsx @@ -0,0 +1,22 @@ +import { useState } from 'react'; + +export default function Component4() { + const [items, setItems] = useState([]); + + const addItem = () => { + const newItem = `Item ${items.length + 1}`; + setItems([...items, newItem]); + }; + + return ( +
+

List Component

+ +
    + {items.map((item, index) => ( +
  • {item}
  • + ))} +
+
+ ); +} diff --git a/src/test/test_cases/tc_14/components/Component5.jsx b/src/test/test_cases/tc_14/components/Component5.jsx new file mode 100644 index 0000000..ad3cb4d --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component5.jsx @@ -0,0 +1,19 @@ +import { useState } from 'react'; + +function Component5() { + const [isToggled, setIsToggled] = useState(false); + + const handleToggle = () => { + setIsToggled(!isToggled); + }; + + return ( +
+

Toggle Component

+

Status: {isToggled ? 'Enabled' : 'Disabled'}

+ ; +
+ ); +} + +export default Component5; \ No newline at end of file diff --git a/src/test/test_cases/tc_14/components/Component6.jsx b/src/test/test_cases/tc_14/components/Component6.jsx new file mode 100644 index 0000000..96fb6fa --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component6.jsx @@ -0,0 +1,10 @@ +function Component6() { + return ( +
+

Static Component

+

This is a static component without interactivity or state.

+
+ ); +} + +export default Component6; \ No newline at end of file diff --git a/src/test/test_cases/tc_14/components/Component7.jsx b/src/test/test_cases/tc_14/components/Component7.jsx new file mode 100644 index 0000000..3506485 --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component7.jsx @@ -0,0 +1,10 @@ +const Component7 = () => { + return ( +
+

Static Component

+

This is a static component without interactivity or state.

+
+ ); +} + +export default Component7; \ No newline at end of file diff --git a/src/test/test_cases/tc_14/index.js b/src/test/test_cases/tc_14/index.js new file mode 100644 index 0000000..3ee1dcc --- /dev/null +++ b/src/test/test_cases/tc_14/index.js @@ -0,0 +1,8 @@ +// Test Case 14 - Check Component Type + +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './components/App'; + +const root = createRoot(document.getElementById('root')); +root.render(); \ No newline at end of file diff --git a/src/utils/modal.ts b/src/utils/modal.ts new file mode 100644 index 0000000..2a8fcd6 --- /dev/null +++ b/src/utils/modal.ts @@ -0,0 +1,14 @@ +import * as vscode from 'vscode'; + +export async function showNotification({message, timeout = 5000 }: { message: string, timeout?: number }) { + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + cancellable: false + }, + async (progress) => { + progress.report({ increment: 100, message: `${message}` }); + await new Promise((resolve) => setTimeout(resolve, timeout)); + } + ); +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index f2b5ff4..1b8699c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,11 @@ "node_modules", ".vscode-test", "src/webviews", - "node_modules/@types/mocha/index.d.ts" + "node_modules/@types/mocha/index.d.ts", + "node_modules/@types/glob/index.d.ts", + "node_modules/@types/jest/index.d.ts", + "src/test/test_cases/tc_12b/app/layout.jsx", + "src/test/test_cases/tc_12b/app/page.tsx", + "src/test/test_cases" ] } \ No newline at end of file diff --git a/webpack.config.ts b/webpack.config.ts index b695149..868ab3d 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -12,7 +12,6 @@ const extConfig: webpack.Configuration = { resolve: { extensions: ['.ts', '.js'] }, module: { rules: [{ test: /\.ts$/, loader: 'ts-loader' }] }, externals: { vscode: 'vscode' }, - mode: 'development' }; const webviewConfig: webpack.Configuration = { @@ -34,7 +33,6 @@ const webviewConfig: webpack.Configuration = { }, ], }, - mode: 'development' }; export default [webviewConfig, extConfig]; \ No newline at end of file