├── .eslintrc.json ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── README.md ├── json ├── demo.json └── root.json ├── media ├── gifs │ ├── Tree.gif │ └── Upload.gif ├── mv-logo.png ├── mv.svg ├── reset.css └── vscode.css ├── package.json ├── src ├── MVParser.ts ├── SidebarProvider.ts ├── extension.ts ├── getNonce.ts ├── helpers │ └── parserHelpers.js ├── test │ ├── runTest.ts │ └── suite │ │ ├── extension.test.ts │ │ └── index.ts ├── types │ ├── Imports.ts │ └── Tree.ts └── webviews │ ├── components │ ├── App.vue │ ├── MVTree.vue │ └── Tree.vue │ ├── globals.d.ts │ ├── img │ └── logo.png │ ├── pages │ └── App.js │ ├── tsconfig.views.json │ └── webpack.views.config.js ├── tsconfig.json ├── vsc-extension-quickstart.md └── webpack.config.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | }, 19 | "ignorePatterns": [ 20 | "out", 21 | "dist", 22 | "**/*.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | .DS_Store 7 | package-lock.json -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/dist/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/**/*.js", 30 | "${workspaceFolder}/dist/**/*.js" 31 | ], 32 | "preLaunchTask": "tasks: watch-tests" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false, // set this to true to hide the "out" folder with the compiled JS files 5 | "dist": false // set this to true to hide the "dist" folder with the compiled JS files 6 | }, 7 | "search.exclude": { 8 | "out": true, // set this to false to include "out" folder in search results 9 | "dist": true // set this to false to include "dist" folder in search results 10 | }, 11 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 12 | "typescript.tsc.autoDetect": "off" 13 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": [ 10 | "$ts-webpack-watch", 11 | "$tslint-webpack-watch" 12 | ], 13 | "isBackground": true, 14 | "presentation": { 15 | "reveal": "never", 16 | "group": "watchers" 17 | }, 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "watch-tests", 26 | "problemMatcher": "$tsc-watch", 27 | "isBackground": true, 28 | "presentation": { 29 | "reveal": "never", 30 | "group": "watchers" 31 | }, 32 | "group": "build" 33 | }, 34 | { 35 | "label": "tasks: watch-tests", 36 | "dependsOn": [ 37 | "npm: watch", 38 | "npm: watch-tests" 39 | ], 40 | "problemMatcher": [] 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | node_modules/** 5 | src/** 6 | .gitignore 7 | .yarnrc 8 | webpack.config.js 9 | vsc-extension-quickstart.md 10 | **/tsconfig.json 11 | **/.eslintrc.json 12 | **/*.map 13 | **/*.ts 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "mountainvue" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 12 | [![Contributors][contributors-shield]][contributors-url] 13 | [![Forks][forks-shield]][forks-url] 14 | [![Stargazers][stars-shield]][stars-url] 15 | [![Issues][issues-shield]][issues-url] 16 | 17 | [![LinkedIn][linkedin-shield]][linkedin-url] 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 | Logo 26 | 27 | 28 |

MountainVue

29 | 30 |

31 | A developer tool to traverse your Vue component tree 32 |
33 |
34 | 41 |

42 |
43 | 44 | 45 | 46 | 47 |
48 | Table of Contents 49 |
    50 |
  1. 51 | About MountainVue 52 |
  2. 53 |
  3. 54 | Built With 55 |
  4. 56 |
  5. 57 | Installation 58 |
  6. 59 |
  7. Usage
  8. 60 |
  9. Roadmap
  10. 61 |
  11. Contributing
  12. 62 |
  13. License
  14. 63 |
  15. Acknowledgments
  16. 64 |
65 |
66 | 67 | 68 | 69 | 70 | ## About MountainVue 71 | 72 | 73 | 74 | 75 | MountainVue is a VS Code Extension that automatically scans your open workspace for Vue-based components and props to render component tree on extension initialization. 76 | 77 | Features: 78 | * Ability to parse through multi-layer Vue component structure as reusable data. 79 | * Parsing of Vue-based project directories to render a component tree in VS Code sidebar panel (via custom application icon). 80 | * Visualization of state and props utilized through Vuex (Vue’s Flux architecture; e.g. React-Redux). 81 | * Ability to export component tree as shareable visualizations (PDFs) for collaborative environments. 82 | 83 | MountainVue's goal is to extend reach to larger user base that specializes in Vue, bridging gap between communities among UI frameworks/libraries. 84 | 85 |

(back to top)

86 | 87 | 88 | 89 | ### Built With 90 | 91 | 92 | * [Vue.js](https://vuejs.org/) 93 | * [Typescript](https://www.typescriptlang.org/) 94 | * [Javascript](https://www.javascript.com/) 95 | * [HTML](https://devdocs.io/html/) 96 | * [CSS](https://devdocs.io/css/) 97 | 98 | 99 |

(back to top)

100 | 101 | 102 | 103 | 104 | ## Getting Started 105 |
106 | 1. After installing VS Code Extension, Click the MountainVue Icon on the sidebar tab. 107 |
108 |
109 | 2. Click upload button to select an entry point with a .vue file. 110 |
111 |
112 | Logo 113 | 114 | 115 |
116 | 3. The sidebar will now display a component tree. 117 |
118 | Logo 119 | 120 | 121 | 122 | 123 |

(back to top)

124 | 125 | 126 | 127 | 128 | 135 | 136 | 137 | 138 | 139 | ## Roadmap 140 | 141 | - [x] Extension Sidebar listening for 142 | - [x] Complete Abstract Syntax Tree rendering logic for sidebar 143 | - [ ] Ability to parse through .vue Templates 144 | - [ ] Add logic to allow user to directly open a component file in the VS extension workspace from the AST 145 | - [ ] Multi-language Support 146 | - [ ] Chinese 147 | 148 | 149 | See the [open issues](https://github.com/oslabs-beta/MountainVue/issues) for a full list of proposed features (and known issues). 150 | 151 |

(back to top)

152 | 153 | 154 | 155 | 156 | ## Contributing 157 | 158 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 159 | 160 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 161 | Don't forget to give the project a star! Thanks again! 162 | 163 | 1. Fork the Project 164 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 165 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 166 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 167 | 5. Open a Pull Request 168 | 169 |

(back to top)

170 | 171 | 172 | 173 | 179 | 180 | 181 | 182 | 183 | ## Creators 184 | 185 | Sean Lee - [@seanswlee](https://github.com/seanswlee) 186 | 187 | Matt Huang - [@matthewhuang24](https://github.com/matthewhuang24) 188 | 189 | Ryan Lim - [@ryanlim1](https://github.com/ryanlim1) 190 | 191 | Sohee Lee - [@sohee419](https://github.com/sohee419) 192 | 193 | Andy Tsou - [@andytsou19](https://github.com/andytsou19) 194 | 195 | Website: [MountainVue.app](https://mountainvue.app/) 196 | 197 |

(back to top)

198 | 199 | 200 | 201 | 202 | ## Acknowledgments 203 | 204 | 205 | * [Parsing Strategy 1](https://observablehq.com/@ehouais/automatic-vue-js-single-file-components-hierarchy-graph-ge) 206 | * [Parsing Strategy 2](https://www.npmjs.com/package/vue-parser) 207 | * [Vue Component Tree Display](https://www.digitalocean.com/community/tutorials/vuejs-recursive-components) 208 | * [Vue Compiler](https://www.npmjs.com/package/vue-template-compiler) 209 | * [VS Code Extension](https://code.visualstudio.com/api) 210 | 211 | 212 | 213 |

(back to top)

214 | 215 | 216 | 217 | 218 | 219 | [contributors-shield]: https://img.shields.io/github/contributors/oslabs-beta/MountainVue?style=for-the-badge 220 | [contributors-url]: https://github.com/oslabs-beta/MountainVue/graphs/contributors 221 | [forks-shield]: https://img.shields.io/github/forks/oslabs-beta/MountainVue?style=for-the-badge 222 | [forks-url]: https://github.com/oslabs-beta/MountainVue/network/members 223 | [stars-shield]: https://img.shields.io/github/stars/oslabs-beta/MountainVue?style=for-the-badge 224 | [stars-url]: https://github.com/oslabs-beta/MountainVue/stargazers 225 | [issues-shield]: https://img.shields.io/github/issues/oslabs-beta/MountainVue?style=for-the-badge 226 | [issues-url]: https://github.com/oslabs-beta/MountainVue/issues 227 | 229 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555 230 | [linkedin-url]: https://www.linkedin.com/company/mountainvue/ 231 | 232 | -------------------------------------------------------------------------------- /json/demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MountainVueApp", 3 | "children": [ 4 | { 5 | "name": "Problems", 6 | "children": [ 7 | { 8 | "name": "Problem1", 9 | "children": [ 10 | { 11 | "name": "Lorem ipsum" 12 | } 13 | ] 14 | }, 15 | { 16 | "name": "Problem2", 17 | "children": [ 18 | { 19 | "name": "Lorem ipsum" 20 | } 21 | ] 22 | } 23 | ] 24 | }, 25 | { 26 | "name": "Solutions", 27 | "children": [ 28 | { 29 | "name": "Solution1", 30 | "children": [ 31 | { 32 | "name": "Lorem ipsum" 33 | } 34 | ] 35 | }, 36 | { 37 | "name": "Solution2", 38 | "children": [ 39 | { 40 | "name": "Lorem ipsum" 41 | } 42 | ] 43 | } 44 | ] 45 | }, 46 | { 47 | "name": "Challenges", 48 | "children": [ 49 | { 50 | "name": "Challenge1", 51 | "children": [ 52 | { 53 | "name": "Lorem ipsum" 54 | } 55 | ] 56 | }, 57 | { 58 | "name": "Challenge2", 59 | "children": [ 60 | { 61 | "name": "Lorem ipsum" 62 | } 63 | ] 64 | } 65 | ] 66 | }, 67 | { 68 | "name": "ComingSoon", 69 | "children": [ 70 | { 71 | "name": "Feature1", 72 | "children": [ 73 | { 74 | "name": "Lorem ipsum" 75 | } 76 | ] 77 | }, 78 | { 79 | "name": "Feature2", 80 | "children": [ 81 | { 82 | "name": "Lorem ipsum" 83 | } 84 | ] 85 | }, 86 | { 87 | "name": "Feature3", 88 | "children": [ 89 | { 90 | "name": "Lorem ipsum" 91 | } 92 | ] 93 | } 94 | ] 95 | }, 96 | { 97 | "name": "Team", 98 | "children": [ 99 | { 100 | "name": "Ryan" 101 | }, 102 | { 103 | "name": "Matt" 104 | }, 105 | { 106 | "name": "Sohee" 107 | }, 108 | { 109 | "name": "Sean" 110 | }, 111 | { 112 | "name": "Andy" 113 | }, 114 | { 115 | "name": "Uni" 116 | } 117 | ] 118 | } 119 | ] 120 | } -------------------------------------------------------------------------------- /json/root.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App.vue", 3 | "children": [ 4 | { 5 | "name": "Home.vue", 6 | "children": [ 7 | { 8 | "name": "Navbar.vue" 9 | }, 10 | { 11 | "name": "Splash.vue" 12 | }, 13 | { 14 | "name": "ComingSoon.vue" 15 | } 16 | ] 17 | }, 18 | { 19 | "name": "About.vue", 20 | "children": [ 21 | { 22 | "name": "Installation.vue", 23 | "children": [ 24 | { 25 | "name": "Directions.vue" 26 | } 27 | ] 28 | }, 29 | { 30 | "name": "Usage.vue" 31 | }, 32 | { 33 | "name": "Contributions.vue" 34 | }, 35 | { 36 | "name": "Acknowledgements.vue" 37 | } 38 | ] 39 | }, 40 | { 41 | "name": "Team.vue", 42 | "children": [ 43 | { 44 | "name": "Ryan.vue" 45 | }, 46 | { 47 | "name": "Matt.vue" 48 | }, 49 | { 50 | "name": "Sohee.vue" 51 | }, 52 | { 53 | "name": "Sean.vue" 54 | }, 55 | { 56 | "name": "Andy.vue" 57 | }, 58 | { 59 | "name": "Uni.vue" 60 | } 61 | ] 62 | } 63 | ] 64 | } -------------------------------------------------------------------------------- /media/gifs/Tree.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/MountainVue/29d3401d894ee20cff664c28f19c27348e49a4b3/media/gifs/Tree.gif -------------------------------------------------------------------------------- /media/gifs/Upload.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/MountainVue/29d3401d894ee20cff664c28f19c27348e49a4b3/media/gifs/Upload.gif -------------------------------------------------------------------------------- /media/mv-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/MountainVue/29d3401d894ee20cff664c28f19c27348e49a4b3/media/mv-logo.png -------------------------------------------------------------------------------- /media/mv.svg: -------------------------------------------------------------------------------- 1 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /media/reset.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 13px; 4 | } 5 | 6 | *, 7 | *:before, 8 | *:after { 9 | box-sizing: inherit; 10 | } 11 | 12 | body, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | p, 20 | ol, 21 | ul { 22 | margin: 0; 23 | padding: 0; 24 | font-weight: normal; 25 | } 26 | 27 | img { 28 | max-width: 100%; 29 | height: auto; 30 | } -------------------------------------------------------------------------------- /media/vscode.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --container-padding: 20px; 3 | --input-padding-vertical: 6px; 4 | --input-padding-horizontal: 4px; 5 | --input-margin-vertical: 4px; 6 | --input-margin-horizontal: 0; 7 | } 8 | 9 | body { 10 | padding: 0 var(--container-padding); 11 | color: var(--vscode-foreground); 12 | font-size: var(--vscode-font-size); 13 | font-weight: var(--vscode-font-weight); 14 | font-family: var(--vscode-font-family); 15 | background-color: var(--vscode-editor-background); 16 | } 17 | 18 | ol, 19 | ul { 20 | padding-left: var(--container-padding); 21 | } 22 | 23 | body > *, 24 | form > * { 25 | margin-block-start: var(--input-margin-vertical); 26 | margin-block-end: var(--input-margin-vertical); 27 | } 28 | 29 | *:focus { 30 | outline-color: var(--vscode-focusBorder) !important; 31 | } 32 | 33 | a { 34 | color: var(--vscode-textLink-foreground); 35 | } 36 | 37 | a:hover, 38 | a:active { 39 | color: var(--vscode-textLink-activeForeground); 40 | } 41 | 42 | code { 43 | font-size: var(--vscode-editor-font-size); 44 | font-family: var(--vscode-editor-font-family); 45 | } 46 | 47 | button { 48 | border: none; 49 | padding: var(--input-padding-vertical) var(--input-padding-horizontal); 50 | width: 100%; 51 | text-align: center; 52 | outline: 1px solid transparent; 53 | outline-offset: 2px !important; 54 | color: var(--vscode-button-foreground); 55 | background: var(--vscode-button-background); 56 | } 57 | 58 | button:hover { 59 | cursor: pointer; 60 | background: var(--vscode-button-hoverBackground); 61 | } 62 | 63 | button:focus { 64 | outline-color: var(--vscode-focusBorder); 65 | } 66 | 67 | button.secondary { 68 | color: var(--vscode-button-secondaryForeground); 69 | background: var(--vscode-button-secondaryBackground); 70 | } 71 | 72 | button.secondary:hover { 73 | background: var(--vscode-button-secondaryHoverBackground); 74 | } 75 | 76 | input:not([type='checkbox']), 77 | textarea { 78 | display: block; 79 | width: 100%; 80 | border: none; 81 | font-family: var(--vscode-font-family); 82 | padding: var(--input-padding-vertical) var(--input-padding-horizontal); 83 | color: var(--vscode-input-foreground); 84 | outline-color: var(--vscode-input-border); 85 | background-color: var(--vscode-input-background); 86 | } 87 | 88 | input::placeholder, 89 | textarea::placeholder { 90 | color: var(--vscode-input-placeholderForeground); 91 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mountainvue", 3 | "displayName": "MountainVue", 4 | "publisher": "MountainVue", 5 | "description": "TBA", 6 | "version": "0.0.1", 7 | "engines": { 8 | "vscode": "^1.62.0" 9 | }, 10 | "categories": [ 11 | "Visualization" 12 | ], 13 | "keywords": [ 14 | "vue", 15 | "vs code extension", 16 | "component hierarchy", 17 | "devtools" 18 | ], 19 | "activationEvents": [ 20 | "onStartupFinished" 21 | ], 22 | "main": "./dist/extension.js", 23 | "contributes": { 24 | "viewsContainers": { 25 | "activitybar": [ 26 | { 27 | "id": "mv-sidebar-view", 28 | "title": "MountainVue", 29 | "icon": "media/mv.svg" 30 | } 31 | ] 32 | }, 33 | "views": { 34 | "mv-sidebar-view": [ 35 | { 36 | "type": "webview", 37 | "id": "mv-sidebar", 38 | "name": "MountainVue", 39 | "icon": "media/mv.svg", 40 | "contextualTitle": "MountainVue" 41 | } 42 | ] 43 | }, 44 | "commands": [] 45 | }, 46 | "scripts": { 47 | "vscode:prepublish": "npm run package", 48 | "build": "concurrently \"cross-env NODE_ENV=development \" \"webpack\" \"npm-run-all -p build:*\"", 49 | "build:extension": "webpack --mode production", 50 | "build:sidebar": "webpack --config ./src/webviews/webpack.views.config.js", 51 | "watch": "webpack --watch", 52 | "package": "webpack --mode production --devtool hidden-source-map", 53 | "compile-tests": "tsc -p . --outDir out", 54 | "watch-tests": "tsc -p . -w --outDir out", 55 | "pretest": "npm run compile-tests && npm run compile && npm run lint", 56 | "lint": "eslint src --ext ts", 57 | "test": "node ./out/test/runTest.js" 58 | }, 59 | "devDependencies": { 60 | "@babel/parser": "^7.16.2", 61 | "@babel/types": "^7.16.0", 62 | "@types/esprima": "^4.0.3", 63 | "@types/glob": "^7.1.4", 64 | "@types/mocha": "^9.0.0", 65 | "@types/node": "14.x", 66 | "@types/vscode": "^1.62.0", 67 | "@types/vue": "^2.0.0", 68 | "@typescript-eslint/eslint-plugin": "^5.1.0", 69 | "@typescript-eslint/parser": "^5.1.0", 70 | "@vscode/test-electron": "^1.6.2", 71 | "@vue/cli-plugin-babel": "^4.5.15", 72 | "@vue/cli-service": "^4.5.15", 73 | "@vue/compiler-sfc": "^3.2.22", 74 | "concurrently": "^6.3.0", 75 | "cross-env": "^7.0.3", 76 | "css-loader": "^6.5.1", 77 | "eslint": "^8.1.0", 78 | "esprima": "^4.0.1", 79 | "file-loader": "^6.2.0", 80 | "generate-source-map": "^0.0.5", 81 | "glob": "^7.1.7", 82 | "mini-css-extract-plugin": "^2.4.4", 83 | "mocha": "^9.1.3", 84 | "node-sass": "^6.0.1", 85 | "npm-run-all": "^4.1.5", 86 | "postcss-import": "^14.0.2", 87 | "sass": "^1.43.4", 88 | "sass-loader": "^12.3.0", 89 | "style-loader": "^3.3.1", 90 | "ts-loader": "^9.2.6", 91 | "typescript": "^4.4.4", 92 | "vscode-test": "^1.6.1", 93 | "vue": "^3.2.22", 94 | "vue-loader": "^16.8.3", 95 | "vue-loader-plugin": "^1.3.0", 96 | "vue-style-loader": "^4.1.3", 97 | "vue-template-compiler": "^2.6.14", 98 | "webpack": "^5.52.1", 99 | "webpack-cli": "^4.8.0" 100 | }, 101 | "dependencies": { 102 | "core-js": "^3.19.1", 103 | "fs": "^0.0.1-security", 104 | "path": "^0.12.7", 105 | "register-service-worker": "^1.7.2" 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/MVParser.ts: -------------------------------------------------------------------------------- 1 | // import * as babelParser from '@babel/parser'; 2 | // import * as path from 'path'; 3 | // import * as fs from 'fs'; 4 | // import { getNonce } from "./getNonce"; 5 | // import { File } from '@babel/types'; 6 | // import Tree from './types/Tree'; 7 | // import Imports from './types/Imports'; 8 | 9 | // class MVParser { 10 | // filePath: string; 11 | // tree: Tree | undefined; 12 | 13 | // constructor(path: string) { 14 | // this.filePath = path; 15 | // this.tree = undefined; 16 | // } 17 | 18 | // public parse(): Tree | undefined { 19 | // const root = { 20 | // id: getNonce(), 21 | // name: path.basename(this.filePath).replace(/\.(vue)$/, ''), 22 | // fileName: path.basename(this.filePath), 23 | // path: this.filePath, 24 | // importPath: '/', 25 | // expanded: false, 26 | // depth: 0, 27 | // count: 1, 28 | // thirdParty: false, 29 | // vueRouter: false, 30 | // vuexStore: false, 31 | // children: [], 32 | // parent: [], 33 | // props: {}, 34 | // error: '' 35 | // }; 36 | 37 | // this.tree = root; 38 | // this.parser(root); 39 | 40 | // return this.tree; 41 | // } 42 | 43 | // public getTree(): Tree | undefined { 44 | // return this.tree; 45 | // } 46 | 47 | // public setTree(tree: Tree): void { 48 | // this.filePath = tree.path; 49 | // this.tree = tree; 50 | // } 51 | 52 | // public updateTree(path: string): Tree | undefined { 53 | // let children: any[] = []; 54 | 55 | // const getChildren = (node: Tree): void => { 56 | // const { depth, path, expanded } = node; 57 | // children.push({ depth, path, expanded }); 58 | // }; 59 | 60 | // const balanceDepth = (node: Tree): void => { 61 | // children.forEach(child => { 62 | // if (child.depth === node.depth && child.path === node.path && child.expanded) { 63 | // node.expanded = true; 64 | // } 65 | // }); 66 | // }; 67 | 68 | // const updateChildren = (node: Tree): void => { 69 | // if (node.path === path) { 70 | // node.children.forEach(child => { 71 | // this.traverseTree(getChildren, child); 72 | // }); 73 | 74 | // const newNode = this.parser(node); 75 | 76 | // this.traverseTree(balanceDepth, newNode); 77 | 78 | // children = []; 79 | // } 80 | // }; 81 | 82 | // this.traverseTree(updateChildren, this.tree); 83 | 84 | // return this.tree; 85 | // } 86 | 87 | // public toggleExpanded(id: string, expanded: boolean): Tree | undefined { 88 | // const updateExpanded = (node: Tree): void => { 89 | // if (node.id === id) { 90 | // node.expanded = expanded; 91 | // } 92 | // }; 93 | 94 | // this.traverseTree(updateExpanded, this.tree); 95 | 96 | // return this.tree; 97 | // } 98 | 99 | // private traverseTree(callback: Function, node: Tree | undefined = this.tree): any { 100 | // if (!node) { 101 | // return; 102 | // } 103 | 104 | // callback(node); 105 | 106 | // node.children.forEach(child => { 107 | // this.traverseTree(callback, child); 108 | // }); 109 | // } 110 | 111 | // private parser(tree: Tree): Tree | undefined { 112 | // if (!['\\', '/', '.'].includes(tree.importPath[0])) { 113 | // tree.thirdParty = true; 114 | 115 | // if (tree.fileName === 'vue-router') { 116 | // tree.vueRouter = true; 117 | // } 118 | 119 | // return; 120 | // } 121 | 122 | // const fileName = this.getFileName(tree); 123 | 124 | // if (!fileName) { 125 | // tree.error = 'File does not exist'; 126 | // return; 127 | // } 128 | 129 | // if (tree.parent.includes(tree.path)) { 130 | // return; 131 | // } 132 | 133 | // let ast: babelParser.ParseResult; 134 | 135 | // try { 136 | // ast = babelParser.parse(fs.readFileSync(path.resolve(tree.path), 'utf-8'), { 137 | // sourceType: 'module', 138 | // tokens: true, 139 | // plugins: ['typescript'] 140 | // }); 141 | // } catch (err) { 142 | // tree.error = 'Could not parse uploaded file'; 143 | // return tree; 144 | // } 145 | 146 | // const imports = this.getImports(ast.program.body); 147 | 148 | // // tree.children = this.getVueChildren(ast.tokens, imports, tree); 149 | // // tree.vuexStore = this.checkForVuex(ast.tokens, imports); 150 | // // tree.children.forEach(child => this.parser(child)); 151 | 152 | // return tree; 153 | // } 154 | 155 | // private getFileName(tree: Tree): string | undefined { 156 | // const fileExt = path.extname(tree.path); 157 | // let fileName: string | undefined = tree.fileName; 158 | 159 | // if (!fileExt) { 160 | // const fileDir = fs.readdirSync(path.dirname(tree.path)); 161 | // const regEx = new RegExp(`${tree.fileName}.(vue)$`); 162 | // fileName = fileDir.find(path => path.match(regEx)); 163 | // fileName ? tree.path += path.extname(fileName) : null; 164 | // } 165 | 166 | // return fileName; 167 | // } 168 | 169 | // private getImports(body: { [key: string]: any }[]): Imports { 170 | // const bodyImports = body.filter(item => item.type === 'ImportDeclaration' || 'VariableDeclaration'); 171 | 172 | // const reduceImports = bodyImports.reduce((output, currVal) => { 173 | // if (currVal.type === 'ImportDeclaration') { 174 | // currVal.specifiers.forEach((val: any) => { 175 | // output[val.local.name] = { 176 | // importPath: currVal.source.value, 177 | // importName: val.imported ? val.imported.name : val.local.name 178 | // }; 179 | // }); 180 | // } 181 | 182 | // if (currVal.type === 'VariableDeclaration') { 183 | // const importPath = this.findVarDecImports(currVal.declartions[0]); 184 | 185 | // if (importPath) { 186 | // const importName = currVal.declarations[0].id.name; 187 | // output[currVal.declarations[0].id.name] = { 188 | // importPath, 189 | // importName 190 | // }; 191 | // } 192 | // } 193 | 194 | // return output; 195 | // }, {}); 196 | 197 | // return reduceImports; 198 | // } 199 | 200 | // private findVarDecImports(ast: { [key: string]: any }): any { 201 | // if (ast.hasOwnProperty('callee') && ast.callee.type === 'Import') { 202 | // return ast.arguments[0].value; 203 | // } 204 | 205 | // for (let key in ast) { 206 | // if (ast.hasOwnProperty(key) && typeof ast[key] === 'object' && ast[key]) { 207 | // const importPath = this.findVarDecImports(ast[key]); 208 | // if (importPath) { 209 | // return importPath; 210 | // } 211 | // } 212 | // } 213 | 214 | // return false; 215 | // } 216 | 217 | // // private getVueChildren(tokens: any[], importData: Imports, parentNode: Tree): Tree | undefined { 218 | // // let childNodes: { [key: string]: Tree } = {}; 219 | // // let props: { [key: string]: boolean } = {}; 220 | // // let token: { [key: string]: any }; 221 | 222 | // // tokens.forEach((token, i) => { 223 | // // if (token.type.label === ) 224 | // // }) 225 | // // } 226 | // } 227 | 228 | // export default MVParser; 229 | -------------------------------------------------------------------------------- /src/SidebarProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import getNonce from './getNonce'; 3 | // import MVParser from './MVParser'; 4 | import Tree from './types/Tree'; 5 | export class SidebarProvider implements vscode.WebviewViewProvider { 6 | _view?: vscode.WebviewView; 7 | // parser: MVParser | undefined; 8 | // private readonly context: vscode.ExtensionContext; 9 | 10 | constructor(private readonly _extensionUri: vscode.Uri) { 11 | // this.context = context; 12 | // this._extensionUri = context.extensionUri; 13 | 14 | // const state: Tree | undefined = context.workspaceState.get('mountainvue'); 15 | 16 | // Parsing logic in progress 17 | // if (state) { 18 | // this.parser = new MVParser(state.filePath); 19 | // } 20 | } 21 | 22 | public resolveWebviewView(webviewView: vscode.WebviewView) { 23 | this._view = webviewView; 24 | 25 | webviewView.webview.options = { 26 | // Allow scripts in the webview 27 | enableScripts: true, 28 | 29 | localResourceRoots: [ 30 | this._extensionUri 31 | ], 32 | }; 33 | 34 | webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); 35 | 36 | // Extension reducer in progress 37 | // webviewView.webview.onDidReceiveMessage(async (data) => { 38 | // switch (data.type) { 39 | // case 'onFile': { 40 | // if (!data.type) { 41 | // return; 42 | // } 43 | 44 | // this.parser = new MVParser(data.value); 45 | // this.parser.parse(); 46 | // // this.updateView(); 47 | // break; 48 | // } 49 | // } 50 | // }); 51 | } 52 | 53 | public revive(panel: vscode.WebviewView) { 54 | this._view = panel; 55 | } 56 | 57 | private _getHtmlForWebview(webview: vscode.Webview) { 58 | const styleResetUri = webview.asWebviewUri( 59 | vscode.Uri.joinPath( 60 | this._extensionUri, 'media', 'reset.css') 61 | ); 62 | 63 | const styleVSCodeUri = webview.asWebviewUri( 64 | vscode.Uri.joinPath( 65 | this._extensionUri, 'media', 'vscode.css') 66 | ); 67 | 68 | // const styleMainUri = webview.asWebviewUri( 69 | // vscode.Uri.joinPath( 70 | // this._extensionUri, 'dist', 'style.css') 71 | // ); 72 | 73 | const scriptUri = webview.asWebviewUri( 74 | vscode.Uri.joinPath( 75 | this._extensionUri, 'dist', 'app.js') 76 | ); 77 | 78 | const nonce = getNonce(); 79 | 80 | return ` 81 | 82 | 83 | 84 | 85 | 91 | 92 | 93 | 94 | 95 | MV 96 | 99 | 100 | 101 |
102 | 82 | 83 | 125 | -------------------------------------------------------------------------------- /src/webviews/components/MVTree.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 68 | 69 | -------------------------------------------------------------------------------- /src/webviews/components/Tree.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | 22 | -------------------------------------------------------------------------------- /src/webviews/globals.d.ts: -------------------------------------------------------------------------------- 1 | import * as _vscode from 'vscode'; 2 | 3 | declare global { 4 | const tsvscode: { 5 | postMessage: ({ type: string, value: any }) => void; 6 | }; 7 | } 8 | 9 | export default tsvscode; -------------------------------------------------------------------------------- /src/webviews/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/MountainVue/29d3401d894ee20cff664c28f19c27348e49a4b3/src/webviews/img/logo.png -------------------------------------------------------------------------------- /src/webviews/pages/App.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from '../components/App.vue'; 3 | 4 | createApp(App).mount('#app'); 5 | -------------------------------------------------------------------------------- /src/webviews/tsconfig.views.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "../../dist", 4 | "lib": [ 5 | "dom" 6 | ], 7 | "module": "es6", 8 | "target": "es5", 9 | "jsx": "react", 10 | "allowJs": true, 11 | "moduleResolution": "node", 12 | "sourceMap": true, 13 | } 14 | } -------------------------------------------------------------------------------- /src/webviews/webpack.views.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { VueLoaderPlugin } = require('vue-loader'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | 5 | module.exports = { 6 | entry: path.resolve(__dirname, './pages/App.js'), 7 | mode: 'production', 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.ts?$/, 12 | use: { 13 | loader: 'ts-loader', 14 | options: { 15 | configFile: 'tsconfig.views.json', 16 | appendTsSuffixTo: [/\.vue$/], 17 | }, 18 | }, 19 | exclude: /node_modules/, 20 | }, 21 | { 22 | test: /\.vue$/, 23 | loader: 'vue-loader', 24 | }, 25 | { 26 | test: /\.vue\.(s?[ac]ss)$/, 27 | use: ['vue-style-loader', 'css-loader', 'sass-loader'], 28 | }, 29 | { 30 | test: /(? https://webpack.js.org/configuration/node/ 13 | mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') 14 | 15 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 16 | output: { 17 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 18 | path: path.resolve(__dirname, 'dist'), 19 | filename: 'extension.js', 20 | libraryTarget: 'commonjs2' 21 | }, 22 | externals: { 23 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 24 | // modules added here also need to be added in the .vscodeignore file 25 | }, 26 | resolve: { 27 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 28 | extensions: ['.ts', '.js'] 29 | }, 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.ts$/, 34 | exclude: /node_modules/, 35 | use: [ 36 | { 37 | loader: 'ts-loader' 38 | } 39 | ] 40 | } 41 | ] 42 | }, 43 | devtool: 'nosources-source-map', 44 | infrastructureLogging: { 45 | level: "log", // enables logging required for problem matchers 46 | }, 47 | }; 48 | module.exports = [ extensionConfig ]; --------------------------------------------------------------------------------