From 2e9b9bed09566d63d2f15f1c1f45b6ea3531cda1 Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Mon, 29 Jan 2024 15:38:01 -0800 Subject: [PATCH 1/8] added tests #11-14, changed config to turn off warnings in .eslintrc, updated babel/parser, took out comments in test files, added paths to exclude complie in tsconfig, note: test 14 is not fully working --- .eslintrc.json | 2 +- package-lock.json | 251 ++++++++---------- src/parser.ts | 3 +- src/test/runTest.ts | 3 - src/test/suite/index.ts | 7 - src/test/suite/parser.test.ts | 136 +++++++--- src/test/test_cases/tc_11/components/App1.jsx | 10 + src/test/test_cases/tc_11/components/App2.jsx | 10 + src/test/test_cases/tc_11/index.js | 8 + .../test_cases/tc_12a/components/Navbar.jsx | 31 +++ src/test/test_cases/tc_12a/pages/index.js | 24 ++ src/test/test_cases/tc_12b/app/homepage.jsx | 11 + src/test/test_cases/tc_12b/app/layout.jsx | 15 ++ src/test/test_cases/tc_12b/app/page.jsx | 17 ++ src/test/test_cases/tc_13/components/App.jsx | 14 + .../tc_13/components/Component1.jsx | 7 + .../tc_13/components/Component2.jsx | 7 + .../tc_13/components/Component3.jsx | 7 + src/test/test_cases/tc_13/index.js | 8 + src/test/test_cases/tc_14/components/App.jsx | 14 + .../tc_14/components/Component1.jsx | 17 ++ .../tc_14/components/Component2.jsx | 21 ++ .../tc_14/components/Component3.jsx | 8 + src/test/test_cases/tc_14/index.js | 8 + tsconfig.json | 6 +- 25 files changed, 456 insertions(+), 189 deletions(-) create mode 100644 src/test/test_cases/tc_11/components/App1.jsx create mode 100644 src/test/test_cases/tc_11/components/App2.jsx create mode 100644 src/test/test_cases/tc_11/index.js create mode 100644 src/test/test_cases/tc_12a/components/Navbar.jsx create mode 100644 src/test/test_cases/tc_12a/pages/index.js create mode 100644 src/test/test_cases/tc_12b/app/homepage.jsx create mode 100644 src/test/test_cases/tc_12b/app/layout.jsx create mode 100644 src/test/test_cases/tc_12b/app/page.jsx create mode 100644 src/test/test_cases/tc_13/components/App.jsx create mode 100644 src/test/test_cases/tc_13/components/Component1.jsx create mode 100644 src/test/test_cases/tc_13/components/Component2.jsx create mode 100644 src/test/test_cases/tc_13/components/Component3.jsx create mode 100644 src/test/test_cases/tc_13/index.js create mode 100644 src/test/test_cases/tc_14/components/App.jsx create mode 100644 src/test/test_cases/tc_14/components/Component1.jsx create mode 100644 src/test/test_cases/tc_14/components/Component2.jsx create mode 100644 src/test/test_cases/tc_14/components/Component3.jsx create mode 100644 src/test/test_cases/tc_14/index.js 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/package-lock.json b/package-lock.json index ca3fbe1..6ddb0f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.9.tgz", + "integrity": "sha512-B2L9neXTIyPQoXDm+NtovPvG6VOLWnaXu3BIeVDWwdKFgG30oNa6CqVGiJPDWQwIAK49t9gnQI9c6K6RzabiKw==", "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" }, @@ -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.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.10.tgz", + "integrity": "sha512-IZD8kAM02AW1HRDTPOlz3npFava678pr8Ie9Vp8uRhBROXAv8MXT2pCnGZZAKYdromsNQLHQcfWQ6EOatVLtqA==", "dependencies": { "undici-types": "~5.26.4" } @@ -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==", + "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-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==", - "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.30001580", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz", + "integrity": "sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==", "funding": [ { "type": "opencollective", @@ -6138,11 +6123,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 +6188,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.648", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.648.tgz", + "integrity": "sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==" }, "node_modules/emittery": { "version": "0.13.1", @@ -6669,9 +6654,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" @@ -9897,9 +9882,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 +11079,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 +12486,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.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.0.tgz", + "integrity": "sha512-bdmyXRCXeeNIePv6R6tGPyy20aUobw4Zy8r0LUS2EWO+U+Ke/gYDgsCh7bl5rB6jPpr4r0SZa6dPxBxLooDT3w==", "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 +12511,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/src/parser.ts b/src/parser.ts index 197dc22..709c364 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -278,7 +278,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++) { @@ -314,6 +313,8 @@ export class Parser { useDispatch: 0, useActions: 0, useSelector: 0, + useShallowEqualSelector: 0, + useStore: 0, bindActionCreators: 0, } if (item.type === 'VariableDeclaration') { 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 81fee91..8e19944 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -1,68 +1,118 @@ 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, expect, test } from '@jest/globals'; describe('Parser Test Suite', () => { let parser, tree, file; - // UNPARSED TREE TEST - describe('It initializes correctly', () => { - 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'); + // 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 instantiates an object for the parser class', () => { - expect((parser)).toBeInstanceOf(Parser); + test('Tree should not be undefined', () => { + expect(tree).toBeDefined(); }); - 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('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 0: ONE CHILD - describe('It works for simple apps', () => { - beforeEach(() => { - file = path.join(__dirname, ''); + // 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('It returns an defined object tree when parsed', () => { - expect(tree).toBeDefined(); - //expect(tree).toMatchObject() + 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('Parsed tree has a property called name with value index and one child with name App', () => { + // 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('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(); + }); - // these are the 14 tests we need to test for - - // TEST 1: NESTED CHILDREN - // TEST 2: THIRD PARTY, REACT ROUTER, DESTRUCTURED IMPORTS - // TEST 3: IDENTIFIES REDUX STORE CONNECTION - // TEST 4: ALIASED IMPORTS - // TEST 5: MISSING EXTENSIONS AND UNUSED IMPORTS - // TEST 6: BAD IMPORT OF APP2 FROM APP1 COMPONENT - // TEST 7: SYNTAX ERROR IN APP FILE CAUSES PARSER ERROR - // TEST 8: MULTIPLE PROPS ON ONE COMPONENT - // TEST 9: FINDING DIFFERENT PROPS ACROSS TWO OR MORE IDENTICAL COMPONENTS - // TEST 10: CHECK CHILDREN WORKS AND COMPONENTS WORK - // TEST 11: PARSER DOESN'T BREAK UPON RECURSIVE COMPONENTS - // TEST 12: NEXT.JS APPS (pages version & app router version) - // TEST 13: Variable Declaration Imports and React.lazy Imports - // TEST 14: CHECK IF COMPONENT IS CLIENT OR SERVER (USING HOOKS & DIRECTIVES) => BOOLEAN (priority) + 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'); + }); - // LOU is doing EXTENSION TEST in extension.test.ts + 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('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 is a client component using hooks, Component2 is a client component using directives, and Component3 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); + }); + }); }); 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..9fa1a38 --- /dev/null +++ b/src/test/test_cases/tc_14/components/App.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import Component1 from './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_14/components/Component1.jsx b/src/test/test_cases/tc_14/components/Component1.jsx new file mode 100644 index 0000000..5ac7638 --- /dev/null +++ b/src/test/test_cases/tc_14/components/Component1.jsx @@ -0,0 +1,17 @@ +import { useState } from 'react'; + +export default function Component1() { + const [count, setCount] = useState(0); + + const handleClick = () => { + setCount(count + 1); + }; + + return ( +
+

This is Component 1.

+

Count: {count}

+ ; +
+ ); +} \ 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/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/tsconfig.json b/tsconfig.json index f2b5ff4..e11af21 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,10 @@ "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" ] } \ No newline at end of file From 0f453009a1476837e0ec6da1a0b117ad21a4e8ff Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Tue, 30 Jan 2024 13:10:45 -0800 Subject: [PATCH 2/8] changed vscode error to showNotification func, imported from /src/utils, to allow programmatic dissmisal of modal if no file was selected --- src/extension.ts | 3 ++- src/utils/modal.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/utils/modal.ts 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/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 From 74a4dcd416e4d926b3ad8452c46ef578088aacee Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Wed, 31 Jan 2024 15:43:33 -0800 Subject: [PATCH 3/8] added more test components for tc_14 to test more component declarations and added test suite in parser.test.ts --- src/test/suite/parser.test.ts | 15 ++++++++++--- .../tc_14/components/Component1.jsx | 6 +++-- .../tc_14/components/Component4.jsx | 22 +++++++++++++++++++ .../tc_14/components/Component5.jsx | 19 ++++++++++++++++ 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/test/test_cases/tc_14/components/Component4.jsx create mode 100644 src/test/test_cases/tc_14/components/Component5.jsx diff --git a/src/test/suite/parser.test.ts b/src/test/suite/parser.test.ts index 8e19944..7edf6e4 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -104,15 +104,24 @@ describe('Parser Test Suite', () => { expect(tree.children[0]).toHaveProperty('name', 'App'); }); - test('App should have three children, Component1 is a client component using hooks, Component2 is a client component using directives, and Component3 is not a client component', () => { - // expect(tree.children[0].children[0]).toHaveProperty('name', 'Component1'); - // expect(tree.children[0].children[0]).toHaveProperty('isClientComponent', true); + test('App should have three children, Component1 is a client component using hooks (variable declaration, export default declaration, and function declaration), Component2 is a client component using directives, and Component3 is not a client component', () => { + expect(tree.children[0].children[0]).toHaveProperty('name', 'Component1'); + expect(tree.children[0].children[0]).toHaveProperty('isClientComponent', true); + expect(typeof tree.children[0].children[0]).toBe('function'); + expect(typeof tree.children[0].children[0]).not.toBe('undefined'); + expect(typeof tree.children[0].children[0]).not.toBe('function'); 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); }); }); }); diff --git a/src/test/test_cases/tc_14/components/Component1.jsx b/src/test/test_cases/tc_14/components/Component1.jsx index 5ac7638..6c7745b 100644 --- a/src/test/test_cases/tc_14/components/Component1.jsx +++ b/src/test/test_cases/tc_14/components/Component1.jsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -export default function Component1() { +const Component1 = () => { const [count, setCount] = useState(0); const handleClick = () => { @@ -14,4 +14,6 @@ export default function Component1() { ; ); -} \ No newline at end of file +} + +export default Component1; \ 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 From 25ff1eeae61002d3c8af6c96c344781014eea415 Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Wed, 31 Jan 2024 16:19:14 -0800 Subject: [PATCH 4/8] got ts errors with parent prop, changed it to match the tree type, added my testing suite to this branch and files, all of the tests in 14 works except the component1. not sure why --- src/parser.ts | 93 +++++++++- src/test/suite/parser.test.ts | 168 +++++++++---------- src/test/test_cases/tc_14/components/App.jsx | 4 + 3 files changed, 172 insertions(+), 93 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index 709c364..be6c8f8 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: '', @@ -61,7 +61,7 @@ export class Parser { } public getTree(): Tree { - return this.tree; + return this.tree!; } // Set entryFile property with the result of Parser (from workspace state) @@ -270,7 +270,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:', @@ -290,8 +290,18 @@ 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; + // console.log('body: ', bodyCallee); + + // Checks for components declared using 'export default function' + const exportCallee = body.filter((item) => item.type === 'ExportDefaultDeclaration'); + // console.log('exprt: ', exportCallee); + + // Checks for components declared using 'function' + const functionCallee = body.filter((item) => item.type === 'FunctionDeclaration'); + // console.log('func: ', functionCallee); // Helper function const calleeHelper = (item) => { @@ -345,7 +355,74 @@ export class Parser { return false; } - if (bodyCallee.length === 1) { + // Calling helper function for functionCallee array with length of 1 or more + if (functionCallee.length === 1) { + const calleeArr = functionCallee[0].body?.body; + if (calleeArr === undefined) return false; + + let checkTrue = false; + for (let i = 0; i < calleeArr.length; i++) { + if (checkTrue) return true; + checkTrue = calleeHelper(calleeArr[i]); + } + return checkTrue; + } else if (functionCallee.length > 1) { + let calleeArr: [] = []; + for (let i = 0; i < functionCallee.length; i++) { + try { + if (functionCallee[i].declarations[0]?.init?.body?.body) { + calleeArr = functionCallee[i].declarations[0].init.body.body; + } + } + catch (err) { + const error = defaultErr(err); + console.error(error.method, '\n', error.log); + } + } + + if (calleeArr === undefined) return false; + let checkTrue = false; + for (let i = 0; i < calleeArr.length; i++) { + if (checkTrue) return true; + checkTrue = calleeHelper(calleeArr[i]); + } + return checkTrue; + + // Calling helper function for exportCallee array with length of 1 or more + } else if (exportCallee.length === 1) { + const calleeArr = exportCallee[0].declaration.body?.body; + if (calleeArr === undefined) return false; + + let checkTrue = false; + for (let i = 0; i < calleeArr.length; i++) { + if (checkTrue) return true; + checkTrue = calleeHelper(calleeArr[i]); + } + return checkTrue; + } else if (exportCallee.length > 1) { + let calleeArr: [] = []; + for (let i = 0; i < exportCallee.length; i++) { + try { + if (exportCallee[i].declarations[0]?.init?.body?.body) { + calleeArr = exportCallee[i].declarations[0].init.body.body; + } + } + catch (err) { + const error = defaultErr(err); + console.error(error.method, '\n', error.log); + } + } + + if (calleeArr === undefined) return false; + let checkTrue = false; + for (let i = 0; i < calleeArr.length; i++) { + if (checkTrue) return true; + checkTrue = calleeHelper(calleeArr[i]); + } + return checkTrue; + + // Calling helper function for bodyCallee array with length of 1 or more + } else if (bodyCallee.length === 1) { const calleeArr = bodyCallee[0].declarations[0]?.init?.body?.body; if (calleeArr === undefined) return false; @@ -355,9 +432,8 @@ export class Parser { checkTrue = calleeHelper(calleeArr[i]); } return checkTrue; - } - else if (bodyCallee.length > 1) { - let calleeArr: []; + } else if (bodyCallee.length > 1) { + let calleeArr: [] = []; for (let i = 0; i < bodyCallee.length; i++) { try { if (bodyCallee[i].declarations[0]?.init?.body?.body) { @@ -378,6 +454,7 @@ export class Parser { } return checkTrue; } + if (!bodyCallee && !exportCallee && !functionCallee) return false; } // Finds JSX React Components in current file diff --git a/src/test/suite/parser.test.ts b/src/test/suite/parser.test.ts index 7edf6e4..f429303 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -6,89 +6,89 @@ describe('Parser Test Suite', () => { let parser, tree, file; // 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('Tree should not be undefined', () => { - expect(tree).toBeDefined(); - }); - - 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 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('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'); - }); - }); + // 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('Tree should not be undefined', () => { + // expect(tree).toBeDefined(); + // }); + + // 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 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('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('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 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('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', () => { @@ -96,6 +96,7 @@ describe('Parser Test Suite', () => { file = path.join(__dirname, '../../../../src/test/test_cases/tc_14/index.js'); parser = new Parser(file); tree = parser.parse(); + // console.log('tree:', tree.children[0].children[0]); }); test('Root should be named index, it should have one children named App', () => { @@ -107,9 +108,6 @@ describe('Parser Test Suite', () => { test('App should have three children, Component1 is a client component using hooks (variable declaration, export default declaration, and function declaration), Component2 is a client component using directives, and Component3 is not a client component', () => { expect(tree.children[0].children[0]).toHaveProperty('name', 'Component1'); expect(tree.children[0].children[0]).toHaveProperty('isClientComponent', true); - expect(typeof tree.children[0].children[0]).toBe('function'); - expect(typeof tree.children[0].children[0]).not.toBe('undefined'); - expect(typeof tree.children[0].children[0]).not.toBe('function'); expect(tree.children[0].children[1]).toHaveProperty('name', 'Component2'); expect(tree.children[0].children[1]).toHaveProperty('isClientComponent', true); diff --git a/src/test/test_cases/tc_14/components/App.jsx b/src/test/test_cases/tc_14/components/App.jsx index 9fa1a38..4536348 100644 --- a/src/test/test_cases/tc_14/components/App.jsx +++ b/src/test/test_cases/tc_14/components/App.jsx @@ -2,6 +2,8 @@ import React from 'react'; import Component1 from './Component1'; import Component2 from "./Component2"; import Component3 from "./Component3"; +import Component4 from "./Component4"; +import Component5 from "./Component5"; export default function Pages() { return ( @@ -9,6 +11,8 @@ export default function Pages() { + + ); } \ No newline at end of file From b4c7088c8a4fd49c50d1062741b4bf043db18555 Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Wed, 31 Jan 2024 16:20:39 -0800 Subject: [PATCH 5/8] added comment in parser.test.ts for other code reviewers --- src/test/suite/parser.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/suite/parser.test.ts b/src/test/suite/parser.test.ts index f429303..fef5210 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -106,6 +106,8 @@ describe('Parser Test Suite', () => { }); test('App should have three children, Component1 is a client component using hooks (variable declaration, export default declaration, and function declaration), Component2 is a client component using directives, and Component3 is not a client component', () => { + // these first two doesnt work but the other tests in this test suite does + // gives me false instead of true expect(tree.children[0].children[0]).toHaveProperty('name', 'Component1'); expect(tree.children[0].children[0]).toHaveProperty('isClientComponent', true); From 92fa73cba9684b894afb9410e2dea40b7c2d9541 Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Wed, 31 Jan 2024 20:16:15 -0800 Subject: [PATCH 6/8] changed logic in parser.ts to skip a conditional if no body array is found based on the type. all the tests in tc_14 are now passing. --- src/parser.ts | 228 ++++++++++++++++++++-------------- src/test/suite/parser.test.ts | 3 - 2 files changed, 137 insertions(+), 94 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index be6c8f8..435ebcd 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -291,17 +291,18 @@ export class Parser { // Second check for use of React/Redux hooks + console.log('body:', body); // Checks for components declared using 'const' const bodyCallee = body.filter((item) => item.type === 'VariableDeclaration'); - // console.log('body: ', bodyCallee); + console.log('bodyCall: ', bodyCallee); // Checks for components declared using 'export default function' const exportCallee = body.filter((item) => item.type === 'ExportDefaultDeclaration'); - // console.log('exprt: ', exportCallee); + console.log('exprt: ', exportCallee); // Checks for components declared using 'function' const functionCallee = body.filter((item) => item.type === 'FunctionDeclaration'); - // console.log('func: ', functionCallee); + console.log('func: ', functionCallee); // Helper function const calleeHelper = (item) => { @@ -356,105 +357,150 @@ export class Parser { } // Calling helper function for functionCallee array with length of 1 or more - if (functionCallee.length === 1) { - const calleeArr = functionCallee[0].body?.body; - if (calleeArr === undefined) return false; - - let checkTrue = false; - for (let i = 0; i < calleeArr.length; i++) { - if (checkTrue) return true; - checkTrue = calleeHelper(calleeArr[i]); - } - return checkTrue; - } else if (functionCallee.length > 1) { - let calleeArr: [] = []; - for (let i = 0; i < functionCallee.length; i++) { - try { - if (functionCallee[i].declarations[0]?.init?.body?.body) { - calleeArr = functionCallee[i].declarations[0].init.body.body; - } - } - catch (err) { - const error = defaultErr(err); - console.error(error.method, '\n', error.log); - } - } + // if (functionCallee.length === 1) { + // const calleeArr = functionCallee[0].body?.body; + // if (calleeArr === undefined) return false; + + // let checkTrue = false; + // for (let i = 0; i < calleeArr.length; i++) { + // if (checkTrue) return true; + // checkTrue = calleeHelper(calleeArr[i]); + // } + // return checkTrue; + // } else if (functionCallee.length > 1) { + // let calleeArr: [] = []; + // for (let i = 0; i < functionCallee.length; i++) { + // try { + // if (functionCallee[i].declarations[0]?.init?.body?.body) { + // calleeArr = functionCallee[i].declarations[0].init.body.body; + // } + // } + // catch (err) { + // const error = defaultErr(err); + // console.error(error.method, '\n', error.log); + // } + // } + + // if (calleeArr === undefined) return false; + // let checkTrue = false; + // for (let i = 0; i < calleeArr.length; i++) { + // if (checkTrue) return true; + // checkTrue = calleeHelper(calleeArr[i]); + // } + // return checkTrue; + // } - if (calleeArr === undefined) return false; - let checkTrue = false; - for (let i = 0; i < calleeArr.length; i++) { - if (checkTrue) return true; - checkTrue = calleeHelper(calleeArr[i]); - } - return checkTrue; // Calling helper function for exportCallee array with length of 1 or more - } else if (exportCallee.length === 1) { - const calleeArr = exportCallee[0].declaration.body?.body; - if (calleeArr === undefined) return false; - - let checkTrue = false; - for (let i = 0; i < calleeArr.length; i++) { - if (checkTrue) return true; - checkTrue = calleeHelper(calleeArr[i]); - } - return checkTrue; - } else if (exportCallee.length > 1) { - let calleeArr: [] = []; - for (let i = 0; i < exportCallee.length; i++) { - try { - if (exportCallee[i].declarations[0]?.init?.body?.body) { - calleeArr = exportCallee[i].declarations[0].init.body.body; - } - } - catch (err) { - const error = defaultErr(err); - console.error(error.method, '\n', error.log); - } - } + // if (exportCallee.length === 1) { + // const calleeArr = exportCallee[0].declaration.body?.body; + // if (calleeArr === undefined) return false; + + // let checkTrue = false; + // for (let i = 0; i < calleeArr.length; i++) { + // if (checkTrue) return true; + // checkTrue = calleeHelper(calleeArr[i]); + // } + // return checkTrue; + // } else if (exportCallee.length > 1) { + // let calleeArr: [] = []; + // for (let i = 0; i < exportCallee.length; i++) { + // try { + // if (exportCallee[i].declarations[0]?.init?.body?.body) { + // calleeArr = exportCallee[i].declarations[0].init.body.body; + // } + // } + // catch (err) { + // const error = defaultErr(err); + // console.error(error.method, '\n', error.log); + // } + // } + + // if (calleeArr === undefined) return false; + // let checkTrue = false; + // for (let i = 0; i < calleeArr.length; i++) { + // if (checkTrue) return true; + // checkTrue = calleeHelper(calleeArr[i]); + // } + // return checkTrue; + // } - if (calleeArr === undefined) return false; - let checkTrue = false; - for (let i = 0; i < calleeArr.length; i++) { - if (checkTrue) return true; - checkTrue = calleeHelper(calleeArr[i]); - } - return checkTrue; + // console.log('hello'); + // // Calling helper function for bodyCallee array with length of 1 or more + // if (bodyCallee.length === 1) { + // console.log('body in length: ', bodyCallee); + // const calleeArr = bodyCallee[0].declarations[0]?.init?.body?.body; + // console.log('calle: ', calleeArr); + // if (calleeArr === undefined) return false; + + // let checkTrue = false; + // for (let i = 0; i < calleeArr.length; i++) { + // if (checkTrue) return true; + // console.log('i:', calleeArr[i]) + // checkTrue = calleeHelper(calleeArr[i]); + // } + // 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); + // } + // } + + // if (calleeArr === undefined) return false; + // let checkTrue = false; + // for (let i = 0; i < calleeArr.length; i++) { + // if (checkTrue) return true; + // checkTrue = calleeHelper(calleeArr[i]); + // } + // return checkTrue; + // } + // if (!bodyCallee && !exportCallee && !functionCallee) return false; - // Calling helper function for bodyCallee array with length of 1 or more - } else 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]); - } - 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); + 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 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; + } + } + } + + // 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; } - if (!bodyCallee && !exportCallee && !functionCallee) return false; + + return false; } // Finds JSX React Components in current file diff --git a/src/test/suite/parser.test.ts b/src/test/suite/parser.test.ts index fef5210..29bd426 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -96,7 +96,6 @@ describe('Parser Test Suite', () => { file = path.join(__dirname, '../../../../src/test/test_cases/tc_14/index.js'); parser = new Parser(file); tree = parser.parse(); - // console.log('tree:', tree.children[0].children[0]); }); test('Root should be named index, it should have one children named App', () => { @@ -106,8 +105,6 @@ describe('Parser Test Suite', () => { }); test('App should have three children, Component1 is a client component using hooks (variable declaration, export default declaration, and function declaration), Component2 is a client component using directives, and Component3 is not a client component', () => { - // these first two doesnt work but the other tests in this test suite does - // gives me false instead of true expect(tree.children[0].children[0]).toHaveProperty('name', 'Component1'); expect(tree.children[0].children[0]).toHaveProperty('isClientComponent', true); From cf696dab760fac585d65f837a046235baacd2fdc Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Thu, 1 Feb 2024 21:25:12 -0800 Subject: [PATCH 7/8] uncommented the other working tests #11-14 --- src/parser.ts | 9 +- src/test/suite/parser.test.ts | 164 +++++++++++++++++----------------- 2 files changed, 86 insertions(+), 87 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index 435ebcd..a3715b8 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -290,19 +290,18 @@ export class Parser { } // Second check for use of React/Redux hooks - - console.log('body:', body); + // console.log('body:', body); // Checks for components declared using 'const' const bodyCallee = body.filter((item) => item.type === 'VariableDeclaration'); - console.log('bodyCall: ', bodyCallee); + // console.log('bodyCall: ', bodyCallee); // Checks for components declared using 'export default function' const exportCallee = body.filter((item) => item.type === 'ExportDefaultDeclaration'); - console.log('exprt: ', exportCallee); + // console.log('exprt: ', exportCallee); // Checks for components declared using 'function' const functionCallee = body.filter((item) => item.type === 'FunctionDeclaration'); - console.log('func: ', functionCallee); + // console.log('func: ', functionCallee); // Helper function const calleeHelper = (item) => { diff --git a/src/test/suite/parser.test.ts b/src/test/suite/parser.test.ts index 29bd426..261a649 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -6,89 +6,89 @@ describe('Parser Test Suite', () => { let parser, tree, file; // 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('Tree should not be undefined', () => { - // expect(tree).toBeDefined(); - // }); - - // 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 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('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'); - // }); - // }); + 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('Tree should not be undefined', () => { + expect(tree).toBeDefined(); + }); + + 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 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('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('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 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('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', () => { From 3d47bc15b2dd351b7ad8253e0adbc5c284f427b6 Mon Sep 17 00:00:00 2001 From: ash-t-luu Date: Thu, 1 Feb 2024 22:17:50 -0800 Subject: [PATCH 8/8] changed modules and configs to be ready for prod --- .gitignore | 5 +++-- .vscodeignore | 11 ++++++++--- package.json | 23 +++++++++++++---------- tsconfig.json | 3 ++- webpack.config.ts | 2 -- 5 files changed, 26 insertions(+), 18 deletions(-) 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.json b/package.json index cb88741..715e5a0 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": [ @@ -53,10 +59,6 @@ { "id": "metrics-file", "name": "Metrics" - }, - { - "id": "test", - "name": "Test" } ] }, @@ -68,11 +70,12 @@ ] }, "scripts": { + "vscode:prepublish": "build", "lint": "eslint .", "pretest": "npm run lint", "test": "npx tsc ; node ./build/src/test/runTest.js", - "dev": "webpack --watch", - "webpack": "webpack" + "watch": "webpack --mode development --config webpack.config.ts --watch", + "build": "webpack --mode production --config webpack.config.ts" }, "devDependencies": { "@babel/preset-typescript": "^7.23.3", diff --git a/tsconfig.json b/tsconfig.json index f2b5ff4..ec823c6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,7 @@ "node_modules", ".vscode-test", "src/webviews", - "node_modules/@types/mocha/index.d.ts" + "node_modules/@types/mocha/index.d.ts", + "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