├── .babelrc
├── .eslintrc
├── .gitignore
├── custom.d.ts
├── index.html
├── package.json
├── postcss.config.js
├── readme.md
├── src
├── appUtil
│ ├── checker.ts
│ ├── defaultConfig.ts
│ ├── groupSettings.ts
│ ├── ignoreArr.ts
│ ├── menuTemplate.ts
│ ├── openFolder.ts
│ ├── parser.ts
│ ├── securitySettingsInfo.ts
│ ├── traverse.ts
│ ├── tsestraverse.ts
│ ├── tsmorph.ts
│ └── versionFinder.ts
├── icons
│ ├── Clipboard01.jpg
│ ├── Clipboard02.jpg
│ ├── Clipboard03.jpg
│ ├── Clipboard04.jpg
│ ├── GitHub-Mark-64px.png
│ ├── deleteIcon.svg
│ ├── faraday-logo.png
│ ├── google-docs.svg
│ ├── icon.svg
│ ├── iconTransparent.svg
│ ├── openFolder.svg
│ └── testing.svg
├── main.ts
├── preload.ts
├── renderer
│ ├── App.tsx
│ ├── Slices
│ │ ├── ignoreItemsSlice.ts
│ │ ├── loadingSlice.tsx
│ │ └── testResultSlice.ts
│ ├── components
│ │ ├── IgnoreCards.tsx
│ │ ├── Loader.tsx
│ │ ├── NavBar.tsx
│ │ └── ResultDisplay.tsx
│ ├── index.tsx
│ └── store.ts
└── styles.css
├── tailwind.config.js
├── tsconfig.json
├── webpack.config.js
├── webpack.electron.js
└── webpack.react.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/env",
5 | {
6 | "targets": {
7 | "node": "6"
8 | }
9 | }
10 | ],
11 | "@babel/react"
12 | ]
13 | }
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/typescript-estree",
3 | "plugins": ["@typescript-eslint"],
4 | "rules": {
5 | "@typescript-eslint/rule-name": "error"
6 | }
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/custom.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.svg" {
2 | const content: any;
3 | export default content;
4 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | FaradayJS
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "FaradayJS",
3 | "version": "1.0.0",
4 | "description": "A tool for securing your Electron Application!",
5 | "main": "dist/main.js",
6 | "scripts": {
7 | "start": "npm run build && electron dist/main.js",
8 | "devstart": "npm run build && electron ./dist/main.js",
9 | "dev:react": "concurrently \"webpack serve --hot --open\" ",
10 | "build": "webpack",
11 | "tsc:build": "tsc",
12 | "test": "mocha",
13 | "compile": "webpack --mode production",
14 | "build-installer": "electron-builder"
15 | },
16 | "build": {
17 | "files": [
18 | "dist/**/*",
19 | "package.json"
20 | ],
21 | "extraMetadata": {
22 | "main": "dist/main.js"
23 | },
24 | "appId": "FaradayJS",
25 | "win": {
26 | "target": ["nsis"]
27 | },
28 | "mac":{
29 | "target":["dmg"]
30 | },
31 | "linux":{
32 | "target":["deb"]
33 | },
34 | "nsis": {
35 | "oneClick": false,
36 | "allowToChangeInstallationDirectory": true
37 | },
38 | "dmg":{
39 | "oneClick": false,
40 | "allowToChangeInstallationDirectory": true
41 | },
42 | "deb":{
43 | "oneClick": false,
44 | "allowToChangeInstallationDirectory": true
45 | }
46 | },
47 | "keywords": [],
48 | "author": "",
49 | "license": "ISC",
50 | "devDependencies": {
51 | "@babel/core": "^7.15.0",
52 | "@babel/preset-env": "^7.15.0",
53 | "@babel/preset-react": "^7.14.5",
54 | "@reduxjs/toolkit": "^1.6.1",
55 | "@types/estraverse": "^5.1.1",
56 | "@types/react": "^17.0.24",
57 | "@types/react-dom": "^17.0.9",
58 | "@types/react-router-dom": "^5.1.8",
59 | "@typescript-eslint/eslint-plugin": "^4.29.2",
60 | "@typescript-eslint/parser": "^4.31.1",
61 | "@typescript-eslint/typescript-estree": "^4.29.2",
62 | "assert": "^2.0.0",
63 | "autoprefixer": "^9.8.6",
64 | "babel-loader": "^8.2.2",
65 | "chai": "^4.3.4",
66 | "chai-as-promised": "^7.1.1",
67 | "cross-env": "^7.0.3",
68 | "css-loader": "^6.2.0",
69 | "electron": "^13.1.9",
70 | "electron-builder": "^22.13.1",
71 | "electron-devtools-installer": "^3.2.0",
72 | "electron-is-dev": "^2.0.0",
73 | "electron-webpack": "^2.8.2",
74 | "estraverse": "^5.2.0",
75 | "estraverse-jsx": "^1.4.0",
76 | "html-webpack-plugin": "^5.3.2",
77 | "htmlparser2": "^7.0.0",
78 | "jscodeshift": "^0.13.0",
79 | "mini-css-extract-plugin": "^2.2.0",
80 | "mocha": "^9.1.2",
81 | "postcss": "^7.0.36",
82 | "postcss-loader": "^6.1.1",
83 | "react-ast": "^0.3.1",
84 | "react-redux": "^7.2.5",
85 | "redux": "^4.1.1",
86 | "redux-devtools-extension": "^2.13.9",
87 | "spectron": "^15.0.0",
88 | "style-loader": "^3.2.1",
89 | "svg-url-loader": "^7.1.1",
90 | "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.7",
91 | "ts-loader": "^9.2.5",
92 | "ts-mocha": "^8.0.0",
93 | "ts-morph": "^12.0.0",
94 | "ts-node": "^10.2.1",
95 | "typescript": "^4.4.3",
96 | "webpack": "^5.50.0",
97 | "webpack-cli": "^4.7.2",
98 | "webpack-dev-server": "^3.11.2"
99 | },
100 | "dependencies": {
101 | "concurrently": "^6.2.1",
102 | "npm": "^7.24.0",
103 | "react": "^17.0.2",
104 | "react-dom": "^17.0.2"
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | const tailwindcss = require('tailwindcss');
2 | module.exports = {
3 | plugins: [
4 | tailwindcss('./tailwind.config.js'),
5 | require('autoprefixer'),
6 | ],
7 | // plugins: {
8 | // '@tailwindcss/jit': {},
9 | // autoprefixer: {},
10 | // },
11 | };
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FaradayJS- electron security.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Table of Contents
13 |
14 | - [About](https://github.com/oslabs-beta/FaradayJS/#about-faradayjs)
15 | - [Features](https://github.com/oslabs-beta/FaradayJS/#Features)
16 | - [Download FaradayJS](https://github.com/oslabs-beta/FaradayJS/#download-faradayjs)
17 | - [How to Use](https://github.com/oslabs-beta/FaradayJS/#how-to-use)
18 | - [Team](https://github.com/oslabs-beta/FaradayJS/#our-team)
19 | - [License](https://github.com/oslabs-beta/FaradayJS/#License)
20 | - [Languages & Tools](https://github.com/oslabs-beta/FaradayJS/#languages-and-tools)
21 |
22 | About FaradayJS
23 |
24 | Similar to how the Faraday cage blocks electromagnetic fileds, FaradayJS protects electron developers from settings which would make their applications vulnerable.
25 |
26 | Features
27 |
28 | Download FaradayJS
29 |
30 | FaradayJS can be downloaded for Windows and Mac at our repo's releases page
31 |
32 |
33 | How to Use
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Our Team
46 |
47 | The team at FaradayJS
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Kelsey Flynn
58 | Rosio Reyes
59 | Heeho Kang
60 | Miklós Kertész
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | License
73 |
74 | This product is licensed under the MIT License.
75 |
76 | This open source product is accelerated by [OS Labs](https://opensourcelabs.io/).
77 |
78 |
79 | Languages and Tools:
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/src/appUtil/checker.ts:
--------------------------------------------------------------------------------
1 | import defaultConfig from './defaultConfig'
2 | import settingsInfo from './securitySettingsInfo';
3 | import groupSettings from './groupSettings';
4 | // console.log("settings: ", settingsInfo);
5 |
6 | const checker = (propertiesObj: { [key: string]: any }, version: number) => {
7 | const versionDefaults: any = groupSettings(version)
8 | const testResults: any = [];
9 |
10 | for (let test in versionDefaults) {
11 |
12 | if (versionDefaults[test].hasOwnProperty('failValue')) {
13 | const testProp: any = test;
14 | const testFailValue: any = versionDefaults[test].failValue;
15 | const testResult = {
16 | testProp: testProp,
17 | failValue: testFailValue,
18 | status: 'unknown',
19 | description: 'none',
20 | start: 0,
21 | end: 0
22 | };
23 | // Check if the properties that were grabbed from the users codebase includes this
24 | // setting that was in our default configuration object
25 | if (propertiesObj.hasOwnProperty(testProp)) {
26 | // it was in that object
27 | //identify the lines for start and end
28 | testResult.start = propertiesObj[testProp].start;
29 | testResult.end = propertiesObj[testProp].end;
30 |
31 | // if the value of that setting is equal to the testFail value
32 | // give it a fail status and description
33 | if (propertiesObj[testProp].value === testFailValue) {
34 | testResult.description = versionDefaults[testProp].description;
35 | testResult.status = 'fail';
36 | } else if (propertiesObj[testProp].value === !testFailValue) {
37 | // else if is not equal to the testFail value
38 | // give it a pass status and description
39 | testResult.description = versionDefaults[testProp].description;
40 | testResult.status = 'pass';
41 | }
42 | } else if (versionDefaults[testProp].default == testFailValue) {
43 | // Case that the setting was not in the files
44 | // Check if the default value for the version # is equal to the testFail value
45 | // if so, assign it a fail by default value and description
46 | testResult.status = 'fail by default';
47 | testResult.description = versionDefaults[testProp].description;
48 | } else { //if (versionDefaults[testProp] === !failValue) {
49 | // Case assumes that the setting was not in the files and that
50 | // the default value is not equal to the testFail value
51 | // assign it a pass by default and description
52 | testResult.status = 'pass by default';
53 | testResult.description = versionDefaults[testProp].description;
54 | // continue;
55 | }
56 | testResults.push(testResult);
57 | }
58 | }
59 | return testResults;
60 | };
61 |
62 |
63 | export default checker
--------------------------------------------------------------------------------
/src/appUtil/defaultConfig.ts:
--------------------------------------------------------------------------------
1 | const defaultConfig = {
2 | // Default settings by version
3 | "0.1.0": {
4 | "allowRunningInsecureContent": {
5 | "default": false
6 | },
7 | "contextIsolation": {
8 | "default": false
9 | },
10 | "enableRemoteModule": {
11 | "default": true
12 | },
13 | "experimentalFeatures": {
14 | "default": false
15 | },
16 | ///
17 | "images": {
18 | "default": true
19 | },
20 | //*** TO DO */
21 | "javascript": {
22 | "default": true
23 | },
24 | //*** TO DO */
25 | "nativeWindowOpen": {
26 | "default": false
27 | },
28 | //*** TO DO */
29 | "navigateOnDragDrop": {
30 | "default": false
31 | },
32 | //*** TO DO */
33 | "nodeIntegration": {
34 | "default": true
35 | },
36 | "nodeIntegrationInWorker": {
37 | "default": false
38 | },
39 | //*** TO DO */
40 | "offscreen": {
41 | "default": false
42 | },
43 | "plugins": {
44 | "default": false
45 | },
46 | //*** TO DO */
47 | "safeDialogs": {
48 | "default": false
49 | },
50 | "sandbox": {
51 | "default": false
52 | },
53 | ///
54 | "spellcheck": {
55 | "default": true
56 | },
57 | ///
58 | "textAreasAreResizable": {
59 | "default": true
60 | },
61 | "webSecurity": {
62 | "default": true
63 | },
64 | "webgl": {
65 | "default": true
66 | },
67 | "webviewTag": {
68 | "default": true
69 | }
70 | },
71 | "5.0.0": {
72 | "nodeIntegrationInSubFrames": {
73 | "default": false
74 | },
75 | "allowRunningInsecureContent": {
76 | "default": false
77 | },
78 | "contextIsolation": {
79 | "default": false
80 | },
81 | "enableRemoteModule": {
82 | "default": true
83 | },
84 | "experimentalFeatures": {
85 | "default": false
86 | },
87 | "images": {
88 | "default": true
89 | },
90 | "javascript": {
91 | "default": true
92 | },
93 | "nativeWindowOpen": {
94 | "default": false
95 | },
96 | "navigateOnDragDrop": {
97 | "default": false
98 | },
99 | "nodeIntegration": {
100 | "default": false
101 | },
102 | "nodeIntegrationInWorker": {
103 | "default": false
104 | },
105 | "offscreen": {
106 | "default": false
107 | },
108 | "plugins": {
109 | "default": false
110 | },
111 | "safeDialogs": {
112 | "default": false
113 | },
114 | "sandbox": {
115 | "default": false
116 | },
117 | "spellcheck": {
118 | "default": true
119 | },
120 | "textAreasAreResizable": {
121 | "default": true
122 | },
123 | "webSecurity": {
124 | "default": true
125 | },
126 | "webgl": {
127 | "default": true
128 | },
129 | "webviewTag": {
130 | "default": false
131 | }
132 | },
133 | "10.0.0": {
134 | "allowRunningInsecureContent": {
135 | "default": false
136 | },
137 | "contextIsolation": {
138 | "default": false
139 | },
140 | "enableRemoteModule": {
141 | "default": false
142 | },
143 | "enableWebSQL": {
144 | "default": true
145 | },
146 | "experimentalFeatures": {
147 | "default": false
148 | },
149 | "images": {
150 | "default": true
151 | },
152 | "javascript": {
153 | "default": true
154 | },
155 | "nativeWindowOpen": {
156 | "default": false
157 | },
158 | "navigateOnDragDrop": {
159 | "default": false
160 | },
161 | "nodeIntegration": {
162 | "default": false
163 | },
164 | "nodeIntegrationInSubFrames": {
165 | "default": false
166 | },
167 | "nodeIntegrationInWorker": {
168 | "default": false
169 | },
170 | "offscreen": {
171 | "default": false
172 | },
173 | "plugins": {
174 | "default": false
175 | },
176 | "safeDialogs": {
177 | "default": false
178 | },
179 | "sandbox": {
180 | "default": false
181 | },
182 | "spellcheck": {
183 | "default": true
184 | },
185 | "textAreasAreResizable": {
186 | "default": true
187 | },
188 | "webSecurity": {
189 | "default": true
190 | },
191 | "webgl": {
192 | "default": true
193 | },
194 | "webviewTag": {
195 | "default": false
196 | }
197 | },
198 | "12.0.0": {
199 | "allowRunningInsecureContent": {
200 | "default": false
201 | },
202 | "contextIsolation": {
203 | "default": true
204 | },
205 | "enableRemoteModule": {
206 | "default": false
207 | },
208 | "enableWebSQL": {
209 | "default": true
210 | },
211 | "experimentalFeatures": {
212 | "default": false
213 | },
214 | "images": {
215 | "default": true
216 | },
217 | "javascript": {
218 | "default": true
219 | },
220 | "nativeWindowOpen": {
221 | "default": false
222 | },
223 | "navigateOnDragDrop": {
224 | "default": false
225 | },
226 | "nodeIntegration": {
227 | "default": false
228 | },
229 | "nodeIntegrationInSubFrames": {
230 | "default": false
231 | },
232 | "nodeIntegrationInWorker": {
233 | "default": false
234 | },
235 | "offscreen": {
236 | "default": false
237 | },
238 | "plugins": {
239 | "default": false
240 | },
241 | "safeDialogs": {
242 | "default": false
243 | },
244 | "sandbox": {
245 | "default": false
246 | },
247 | "spellcheck": {
248 | "default": true
249 | },
250 | "textAreasAreResizable": {
251 | "default": true
252 | },
253 | "webSecurity": {
254 | "default": true
255 | },
256 | "webgl": {
257 | "default": true
258 | },
259 | "webviewTag": {
260 | "default": false
261 | }
262 | },
263 | "13.0.0": {
264 | "allowRunningInsecureContent": {
265 | "default": false
266 | },
267 | "contextIsolation": {
268 | "default": true
269 | },
270 | "enableRemoteModule": {
271 | "default": false
272 | },
273 | "enableWebSQL": {
274 | "default": true
275 | },
276 | "experimentalFeatures": {
277 | "default": false
278 | },
279 | "images": {
280 | "default": true
281 | },
282 | "javascript": {
283 | "default": true
284 | },
285 | "nativeWindowOpen": {
286 | "default": false
287 | },
288 | "navigateOnDragDrop": {
289 | "default": false
290 | },
291 | "nodeIntegration": {
292 | "default": false
293 | },
294 | "nodeIntegrationInSubFrames": {
295 | "default": false
296 | },
297 | "nodeIntegrationInWorker": {
298 | "default": false
299 | },
300 | "offscreen": {
301 | "default": false
302 | },
303 | "plugins": {
304 | "default": false
305 | },
306 | "safeDialogs": {
307 | "default": false
308 | },
309 | "sandbox": {
310 | "default": false
311 | },
312 | "spellcheck": {
313 | "default": true
314 | },
315 | "textAreasAreResizable": {
316 | "default": true
317 | },
318 | "webSecurity": {
319 | "default": true
320 | },
321 | "webgl": {
322 | "default": true
323 | },
324 | "webviewTag": {
325 | "default": false
326 | }
327 | },
328 | "15.0.0": {
329 | "allowRunningInsecureContent": {
330 | "default": false
331 | },
332 | "contextIsolation": {
333 | "default": true
334 | },
335 | "enableRemoteModule": {
336 | "default": false
337 | },
338 | "enableWebSQL": {
339 | "default": true
340 | },
341 | "experimentalFeatures": {
342 | "default": false
343 | },
344 | "images": {
345 | "default": true
346 | },
347 | "javascript": {
348 | "default": true
349 | },
350 | "nativeWindowOpen": {
351 | "default": true
352 | },
353 | "navigateOnDragDrop": {
354 | "default": false
355 | },
356 | "nodeIntegration": {
357 | "default": false
358 | },
359 | "nodeIntegrationInSubFrames": {
360 | "default": false
361 | },
362 | "nodeIntegrationInWorker": {
363 | "default": false
364 | },
365 | "offscreen": {
366 | "default": false
367 | },
368 | "plugins": {
369 | "default": false
370 | },
371 | "safeDialogs": {
372 | "default": false
373 | },
374 | // should not add this CLI tag: --no-sandbox that's a testing feature only not for prod code
375 | // https://www.electronjs.org/docs/tutorial/sandbox
376 | "sandbox": {
377 | "default": false
378 | },
379 | "spellcheck": {
380 | "default": true
381 | },
382 | "textAreasAreResizable": {
383 | "default": true
384 | },
385 | "webSecurity": {
386 | "default": true
387 | },
388 | "webgl": {
389 | "default": true
390 | },
391 | "webviewTag": {
392 | "default": false
393 | }
394 | }
395 | }
396 |
397 | export default defaultConfig
--------------------------------------------------------------------------------
/src/appUtil/groupSettings.ts:
--------------------------------------------------------------------------------
1 | import defaultConfig from './defaultConfig'
2 | import settingsInfo from './securitySettingsInfo';
3 |
4 | const groupSettings = (version: number) => {
5 | let userVersionNumber: number = parseInt(version.toString().split(".")[0]);
6 | console.log('version from user: ', userVersionNumber);
7 | const testsObj: any = {};
8 | let versionObj: any = {};
9 | Object.keys(defaultConfig).forEach((str, index) => {
10 | versionObj[parseInt(str.split(".")[0])] = index;
11 | });
12 |
13 | let versionDefaults: any;
14 |
15 | if(userVersionNumber >= 0 && userVersionNumber < 5){
16 | userVersionNumber = 0;
17 | }else if(userVersionNumber>= 5 && userVersionNumber < 10){
18 | userVersionNumber = 5;
19 | }else if(userVersionNumber >= 10 && userVersionNumber < 12){
20 | userVersionNumber = 10;
21 | }else if(userVersionNumber >= 13 && userVersionNumber < 15){
22 | userVersionNumber = 13;
23 | }else if(userVersionNumber >= 15){
24 | userVersionNumber = 15;
25 | }else {
26 | console.log('Using default version 13.0.0');
27 | userVersionNumber = 13;
28 | }
29 | versionDefaults = Object.values(defaultConfig)[versionObj[userVersionNumber]];
30 |
31 | for(const [setting, values] of Object.entries(versionDefaults)){
32 | if(settingsInfo[setting]){
33 | versionDefaults[setting].failValue = settingsInfo[setting].failValue;
34 | versionDefaults[setting].description = settingsInfo[setting].description;
35 | }
36 | }
37 | // add a test for the version, if it is older than version 13
38 | if(userVersionNumber < 13){
39 | console.log('Version needs to be updated');
40 | versionDefaults["needToUpdateVersion"] = {
41 | default: true,
42 | failValue: true,
43 | description: "It is recommended that you update to the latest version of Electron as Electron is continuiously implementing updates and changes that make your application more secure."
44 | };
45 | }
46 |
47 | return versionDefaults;
48 | }
49 |
50 | export default groupSettings
--------------------------------------------------------------------------------
/src/appUtil/ignoreArr.ts:
--------------------------------------------------------------------------------
1 | export const doInclude = ['.js', '.jsx', '.ts', '.tsx', '.html'];
2 | export const doNotInclude = ['.vscode', '.json', 'node_modules', '.txt', 'dist', 'build'];
3 |
4 |
--------------------------------------------------------------------------------
/src/appUtil/menuTemplate.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import { app, BrowserWindow, ipcMain, dialog, Menu } from 'electron';
3 | const isMac = process.platform === 'darwin';
4 |
5 | const menuTemplate = (win) => {
6 | return [
7 | {
8 | label: 'File',
9 | submenu: [
10 | {
11 | label: 'Open File',
12 | accelerator: 'CmdOrCtrl+O',
13 | click: () => {
14 | console.log('opened file');
15 | },
16 | },
17 | { label: 'Open Folder' },
18 | isMac ? { role: 'close' } : { role: 'quit' },
19 | { type: 'separator' },
20 | {
21 | label: 'test-1',
22 | submenu: [{ label: 'test-2' }],
23 | },
24 | ],
25 | },
26 | ...(isMac
27 | ? [
28 | {
29 | label: app.name,
30 | submenu: [
31 | { role: 'about' },
32 | { type: 'separator' },
33 | { role: 'services' },
34 | { type: 'separator' },
35 | { role: 'hide' },
36 | { role: 'hideothers' },
37 | { role: 'unhide' },
38 | { type: 'separator' },
39 | { role: 'quit' },
40 | ],
41 | },
42 | ]
43 | : []),
44 | // { role: 'editMenu' }
45 | {
46 | label: 'Edit',
47 | submenu: [
48 | { role: 'undo' },
49 | { role: 'redo' },
50 | { type: 'separator' },
51 | { role: 'cut' },
52 | { role: 'copy' },
53 | { role: 'paste' },
54 | ...(isMac
55 | ? [
56 | { role: 'pasteAndMatchStyle' },
57 | { role: 'delete' },
58 | { role: 'selectAll' },
59 | { type: 'separator' },
60 | {
61 | label: 'Speech',
62 | submenu: [{ role: 'startSpeaking' }, { role: 'stopSpeaking' }],
63 | },
64 | ]
65 | : [{ role: 'delete' }, { type: 'separator' }, { role: 'selectAll' }]),
66 | ],
67 | },
68 | // { role: 'viewMenu' }
69 | {
70 | label: 'View',
71 | submenu: [
72 | { role: 'reload' },
73 | { role: 'forceReload' },
74 | { role: 'toggleDevTools' },
75 | { type: 'separator' },
76 | { role: 'resetZoom' },
77 | { role: 'zoomIn' },
78 | { role: 'zoomOut' },
79 | { type: 'separator' },
80 | { role: 'togglefullscreen' },
81 | ],
82 | },
83 | // { role: 'windowMenu' }
84 | {
85 | label: 'Window',
86 | submenu: [
87 | { role: 'minimize' },
88 | { role: 'zoom' },
89 | ...(isMac
90 | ? [
91 | { type: 'separator' },
92 | { role: 'front' },
93 | { type: 'separator' },
94 | { role: 'window' },
95 | ]
96 | : [{ role: 'close' }]),
97 | ],
98 | },
99 | {
100 | role: 'help',
101 | submenu: [
102 | {
103 | label: 'Learn More',
104 | click: async () => {
105 | const { shell } = require('electron');
106 | await shell.openExternal('https://electronjs.org');
107 | },
108 | },
109 | ],
110 | },
111 | {
112 | label: 'Developer',
113 | submenu: [
114 | {
115 | label: 'Toggle Developer Tools',
116 | accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
117 | click: () => {
118 | win.webContents.toggleDevTools();
119 | },
120 | },
121 | ],
122 | },
123 | ];
124 | };
125 |
126 | export default menuTemplate;
127 |
--------------------------------------------------------------------------------
/src/appUtil/openFolder.ts:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | import { dialog } from 'electron';
3 |
4 | const OpenFolder = async (win:any, doInclude:string[], doNotInclude:string[]) => {
5 | try {
6 | const folders: Promise | Boolean | String = dialog.showOpenDialog(win, {
7 | properties: ['openDirectory']
8 | });
9 |
10 | const folder = await folders; // // returns {canceled: false, filePaths: [ 'D:\\Codesmith\\Projects\\TestElectron' ]}
11 |
12 | const returnValue: any = {};
13 | returnValue.fileObjectArray = [];
14 | returnValue.packageJsonContents = '';
15 |
16 | const readAllFolder = async (dirMain: string) => {
17 |
18 | const readDirMain = fs.readdirSync(dirMain);
19 |
20 | readDirMain.forEach(async (dirNext: string) => {
21 | const nextDirectory = dirMain + "/" + dirNext;
22 | if (fs.lstatSync(nextDirectory).isDirectory()) {
23 | readAllFolder(nextDirectory);
24 | } else {
25 | if (doInclude.some(el=>nextDirectory.includes(el)) && !doNotInclude.some(el=>nextDirectory.includes(el))){
26 | const fileContent = fs.readFileSync(nextDirectory).toString();
27 | const fileObj: any = {
28 | path: dirMain + '/', //process.platform === 'darwin' ? '/' : '\\',
29 | fileName: dirNext,
30 | contents: fileContent
31 | }
32 | returnValue.fileObjectArray.push(fileObj);
33 | } else if (nextDirectory.includes('package.json')){
34 | returnValue.packageJsonContents = await fs.readFileSync(nextDirectory).toString();
35 | }
36 | }
37 | });
38 | return returnValue;
39 | }
40 |
41 | if(folder.canceled){
42 | return
43 | }else{
44 | return await readAllFolder(folder.filePaths[0]);
45 | }
46 |
47 | } catch(err){
48 | console.log('Open Folder Error: ', err);
49 | }
50 | }
51 |
52 | export default OpenFolder
--------------------------------------------------------------------------------
/src/appUtil/parser.ts:
--------------------------------------------------------------------------------
1 | import * as parse from '@typescript-eslint/typescript-estree'
2 | const htmlparser2 = require('htmlparser2');
3 |
4 | export const parser = async (obj: string) => {
5 | try {
6 | const options = {
7 | jsx: true,
8 | loc: true,
9 | };
10 | const parsed = await parse.parse(obj, options);
11 | return parsed;
12 | } catch (e) {
13 | console.log('Parse Error: ', e);
14 | }
15 | };
16 |
17 | export const htmlparser = (obj: string) => {
18 | //const dom = htmlparser2.parseDocument(obj); // you can see the whole DOM
19 | const tests: any = {
20 | disablewebsecurity: {
21 | default: false,
22 | description: "Related to webSecurity. This allows the execution of insecure code from different domains. It allows CORS requests (an origin is considered the same origin if it has the same protocol, port (if specified) and host), and ignores X-Frame-Options which serve to indicate whether or not, and in what context a browser is allowed to render a page. Enabling this setting disables the same-origin policy and sets allowRunningInsecureContent to true.",
23 | failValue: true,
24 | },
25 | allowpopups: {
26 | default: false,
27 | description: "New windows will open a BrowserWindow using window.open() when nativeWindowOpen is set to true and create a BrowserWindowProxy when nativeWindowOpen is set to false. BrowserWindow by default has complete access to the Node API. Allowing popups and loading insecure content in your application can pose security risks. Node Integration and Javascript will be disabled in the new window if it is also disabled in the parent window. Similarly, context isolation will be enabled if it is enabled in the parent window. It is best to only allow websites to create new popups if you are sure it is necessary. ",
28 | failValue: true
29 | }
30 | }
31 | const testResults: any = [];
32 |
33 | const parsed = new htmlparser2.Parser({
34 | onopentag(
35 | name: string,
36 | attribute: { [key: string]: string | number | boolean | undefined | null }
37 | ) {
38 | for (let test in tests) {
39 | const testResult = {
40 | testProp: test,
41 | failValue: tests[test].failValue,
42 | description: "none",
43 | status: 'unknown',
44 | start: 0,
45 | end: 0
46 | };
47 | if (tests[test].hasOwnProperty('failValue')) {
48 | if (name === 'webview' &&
49 | attribute.hasOwnProperty(test)
50 | ) {
51 | testResult.status = 'fail';
52 | testResult.description = tests[test].description;
53 | console.log('testResult.description: ', testResult.description);
54 | testResults.push(testResult);
55 | } else if (name === 'webview' &&
56 | !attribute.hasOwnProperty(test)
57 | ) {
58 | testResult.status = 'pass by default';
59 | testResult.description = tests[test].description;
60 | console.log('testResult.description: ', testResult.description);
61 | testResults.push(testResult);
62 | }
63 | }
64 | }
65 | },
66 | ontext(text: string) {},
67 | onclosetag(tagname: string) {},
68 | });
69 |
70 | parsed.write(obj);
71 |
72 | parsed.end();
73 |
74 | // loop through keys in tests obj
75 | // checking if that key does NOT exist in testResults
76 | // then push to testResults a testResult obj defined here that has a status of 'pass by default'
77 |
78 |
79 | for (let test in tests) {
80 | // const isResultPresent = testResults.reduce((accum: boolean, currVal: any) => {
81 | // if (currVal.testProp === test) return accum = true;
82 | // }, false);
83 | let isResultPresent: boolean = false;
84 |
85 | testResults.forEach((obj:any) =>{
86 | if(obj.testProp === test){
87 | isResultPresent = true
88 | }
89 | })
90 |
91 | if(!isResultPresent) {
92 | testResults.push({
93 | testProp: test,
94 | failValue: tests[test].failValue,
95 | description: tests[test].description,
96 | status: 'pass by default',
97 | start: 0,
98 | end: 0
99 | });
100 | }
101 | }
102 |
103 | return testResults;
104 | };
105 |
--------------------------------------------------------------------------------
/src/appUtil/securitySettingsInfo.ts:
--------------------------------------------------------------------------------
1 | const settingsInfo : { [key: string]: any } = {
2 | // https://www.electronjs.org/docs/api/browser-window
3 |
4 | // ***************************************************************************
5 | // Found in HTML
6 | "allowpopups": {
7 | "failValue": true,
8 | "description": "New windows will open a BrowserWindow using window.open() when nativeWindowOpen is set to true and create a BrowserWindowProxy when nativeWindowOpen is set to false. BrowserWindow by default has complete access to the Node API. Allowing popups and loading insecure content in your application can pose security risks. Node Integration and Javascript will be disabled in the new window if it is also disabled in the parent window. Similarly, context isolation will be enabled if it is enabled in the parent window. It is best to only allow websites to create new popups if you are sure it is necessary. "
9 | },
10 | "disablewebsecurity": {
11 | "failValue": true,
12 | "description": "Related to webSecurity. This allows the execution of insecure code from different domains. It allows CORS requests (an origin is considered the same origin if it has the same protocol, port (if specified) and host), and ignores X-Frame-Options which serve to indicate whether or not, and in what context a browser is allowed to render a page. Enabling this setting disables the same-origin policy and sets allowRunningInsecureContent to true."
13 | },
14 | // ***************************************************************************
15 | // Found in JS/TS Files
16 | "webSecurity": {
17 | "failValue": false,
18 | "description": "Related to disablewebsecurity. This allows the execution of insecure code from different domains. It allows CORS requests (an origin is considered the same origin if it has the same protocol, port (if specified) and host), and ignores X-Frame-Options which serve to indicate whether or not, and in what context a browser is allowed to render a page. Enabling this setting disables the same-origin policy and sets allowRunningInsecureContent to true."
19 | },
20 | // https://slack.engineering/the-app-sandbox/
21 | "sandbox": {
22 | // best to enable
23 | "failValue": null,
24 | "description": "Sandboxing is a Chromium feature that uses the operating system to significantly limit what renderer processes have access to, which essentially becomes only the ability to send messages to the main process. Enabling this feature means that your renderer process cannot use Node or any external module that depends on any of the core modules of Node. It is a feature used to mitigate the many potential security risks we cannot account for. "
25 | },
26 | "allowRunningInsecureContent": {
27 | "failValue": true,
28 | "description": "Setting this to true disables the default electron settings that prohibit websites loaded over secure sources (HTTPS), to load and execute scripts, CSS, or plugins from insecure sources (HTTP). Depending on the content you load onto your page, this could pose varying levels of security risks."
29 | },
30 | "enableBlinkFeatures": {
31 | // Can have many different values. Property is ideally not declared in files unless there's a clear purpose
32 | // If this is declared in application then it fails this test, regardless of what it's set to
33 | "failValue": true,
34 | "description": "Blink is Chromium's rendering engine and setting this property to true enables features which had been previously disabled, by default, for security purposes. Some blink feratures are the following: KeyboardEventKey and ExecCommandInJavaScript. You should fully understand the security risks of the features you are enanbling and try your best to safeguard your application."
35 | },
36 | "experimentalFeatures": {
37 | "failValue": true,
38 | "description": "The impact of experimentalFeatures on Electron applications has not been tested. If not strictly required do not enable."
39 | },
40 | // ********************************************************************************************************
41 | // TO RESEARCH
42 |
43 | // Enabled by default since Electron 12>=
44 | "contextIsolation": {
45 | "failValue": false,
46 | "description": "Ensures that the preload scripts and the internal logic of your app run in a separate context to the websites loaded in webContents."
47 | },
48 | // Disabled by default since Electron 10>=
49 | "enableRemoteModule": {
50 | "failValue": true,
51 | "description": "Renders sandboxing your renderer useless. Renderer is only as secure as the main process keeps it in check."
52 | },
53 |
54 | "images": {
55 | "failValue": null,
56 | "description": "none"
57 | },
58 | "javascript": {
59 | "failValue": null,
60 | "description": "none"
61 | },
62 | "nativeWindowOpen": {
63 | "failValue": null,
64 | "description": "When set to false window.open results in the creation of a BrowserWindowProxy wrapper around BrowserWindow. Electron pairs the native Chrome window with a BrowserWindow under the hood."
65 | },
66 | "navigateOnDragDrop": {
67 | "failValue": null,
68 | "description": "none"
69 | },
70 | "nodeIntegration": {
71 | "failValue": true,
72 | "description": "Enables/disables the use of NodeJS "
73 | },
74 | "nodeIntegrationInWorker": {
75 | "failValue": true,
76 | "description": "none"
77 | },
78 | "offscreen": {
79 | "failValue": null,
80 | "description": "none"
81 | },
82 | "plugins": {
83 | "failValue": true,
84 | "description": "none"
85 | },
86 | "safeDialogs": {
87 | "failValue": true,
88 | "description": "none"
89 | },
90 | "spellcheck": {
91 | "failValue": null,
92 | "description": "none"
93 | },
94 | "textAreasAreResizable": {
95 | "failValue": null,
96 | "description": "none"
97 | },
98 | // https://security.stackexchange.com/questions/13799/is-webgl-a-security-concern
99 | // best if its disabled but its typically enabled by default, might be necessary
100 | "webgl": {
101 | "failValue": null,
102 | "description": "WebGL is a JS API used to render interactive graphics. It allows direct access to the GPU, so while it can be a potential security concern, most browsers ensure that running your code will not be a major security issue."
103 | },
104 | // Disabled as of Version 5>=
105 | //
106 | //
107 | // can also set within this tag: plugins, preload, disablewebsecurity, allowpopups, webpreferences, partition, useragent
108 | // enableblinkfeatures, disableblinkfeatures
109 | // has methods: loadURL(), downloadURL(), getURL(), getTitle(), isLoading(), isLoadingMainFraim(), isWaitingForResponse(),
110 | // stop(), reload(), reloadIgnoringCache(),......... and MANY MORE
111 | // https://stackoverflow.com/questions/37602759/what-is-the-difference-between-browserwindow-and-webview-tag-in-electron-and-w
112 | // https://www.electronjs.org/docs/api/webview-tag
113 | "webviewTag": {
114 | "failValue": true,
115 | "description": "Used to embed guest content in your application, this tags runs in a separate process than your application and would normally be safe to use, but as it is based on Chromiums webview, which is undergoing major structural changes it is not recommended to use this tag at this time."
116 | },
117 | "enableWebSQL": {
118 | "failValue": null,
119 | "description": "none"
120 | },
121 | "nodeIntegrationInSubFrames": {
122 | "failValue": true,
123 | "description": "none"
124 | }
125 | // ,
126 | // "needToUpdateVersion": {
127 | // "failValue": true,
128 | // "description": "It is recommended that you update to the latest version of Electron as Electron is continuiously implementing updates and changes that make your application more secure."
129 | // }
130 |
131 | }
132 | export default settingsInfo
--------------------------------------------------------------------------------
/src/appUtil/traverse.ts:
--------------------------------------------------------------------------------
1 | const traverser = (node:any, level:number) =>{
2 | let tempCache: {[key:string]:string|number|boolean|undefined|null} = {};
3 |
4 | const traverse = (node:any, level:number) =>{
5 | //const indent = Array(level+1).join(" ");
6 | //console.log(indent, "type:", node.type)
7 |
8 | switch(node.type){
9 | case "Program":
10 | for(let child of node.body){
11 | traverse(child, level+1);
12 | }
13 | break;
14 | case "ImportDeclaration":
15 | break;
16 | case "VariableDeclaration":
17 | for(let child of node.declarations){
18 | traverse(child, level+1)
19 | }
20 | break;
21 | case "VariableDeclarator":
22 | if(node.id !== null){
23 | traverse(node.id, level+1);
24 | }
25 | if(node.init !== null){
26 | traverse(node.init, level+1)
27 | }
28 | break;
29 | case "ExportDefaultDeclaration":
30 | traverse(node.declaration, level+1);
31 | break;
32 | case "ClassDeclaration":
33 | traverse(node.body, level+1);
34 | break;
35 | case "ClassBody":
36 | for(let child of node.body){
37 | traverse(child, level+1);
38 | }
39 | break;
40 | case "ClassProperty":
41 | traverse(node.key, level+1);
42 | traverse(node.value, level+1);
43 | break;
44 | case "Literal":
45 | //console.log(indent, node.value)
46 | break;
47 | case "Identifier":
48 | //console.log(indent, node.name)
49 | break;
50 | case "ArrowFunctionExpression":
51 | traverse(node.body, level+1);
52 | break;
53 | case "FunctionExpression":
54 | traverse(node.body, level+1);
55 | break;
56 | case "BinaryExpression":
57 | traverse(node.left, level+1);
58 | traverse(node.right, level+1);
59 | break;
60 | case "CallExpression":
61 | traverse(node.callee, level+1);
62 | for(let child of node.arguments){
63 | traverse(child, level+1);
64 | }
65 | break;
66 | case "AwaitExpression":
67 | traverse(node.argument, level+1);
68 | break;
69 | case "MemberExpression":
70 | traverse(node.object, level+1);
71 | traverse(node.property, level+1);
72 | break;
73 | case "BlockStatement":
74 | for(let child of node.body){
75 | traverse(child, level+1);
76 | }
77 | break;
78 | case "ExpressionStatement":
79 | traverse(node.expression, level+1)
80 | break;
81 | case "ForOfStatement":
82 | traverse(node.body, level+1)
83 | break;
84 | case "TryStatement":
85 | traverse(node.block, level+1)
86 | traverse(node.handler, level+1)
87 | break;
88 | case "ReturnStatement":
89 | traverse(node.argument, level+1)
90 | break;
91 | case "CatchClause":
92 | traverse(node.param, level+1)
93 | traverse(node.body, level+1)
94 | break;
95 | case "ArrayExpression":
96 | for(let child of node.elements){
97 | traverse(child, level+1)
98 | }
99 | break;
100 | case "UnaryExpression":
101 | traverse(node.argument, level+1)
102 | break;
103 | case "AssignmentExpression":
104 | traverse(node.left, level+1);
105 | traverse(node.right, level+1);
106 | break;
107 | case "NewExpression":
108 | traverse(node.callee, level+1);
109 | for(let child of node.arguments){
110 | traverse(child, level+1)
111 | }
112 | break;
113 | case "ObjectExpression":
114 | for(let child of node.properties){
115 | traverse(child, level+1);
116 | }
117 | break;
118 | case "Property":
119 | traverse(node.key, level+1)
120 | traverse(node.value, level+1)
121 | tempCache[node.key.name] = node.value.value
122 | break;
123 | case "JSXElement":
124 | traverse(node.openingElement, level+1)
125 | traverse(node.closingElement, level+1)
126 | for(let child of node.children){
127 | traverse(child, level+1)
128 | }
129 | break;
130 | case "JSXIdentifier":
131 | //console.log(node.name)
132 | break;
133 | case "IfStatement":
134 | break;
135 | case "TemplateLiteral":
136 | break;
137 | case "ObjectPattern":
138 | for(let child of node.properties){
139 | traverse(child, level+1)
140 | }
141 | break;
142 | default:
143 | throw new Error("Node type not handled")
144 | }
145 | }
146 | //console.log(tempCache)
147 | traverse(node, level);
148 | return tempCache
149 | }
150 |
151 |
152 | export default traverser
153 |
--------------------------------------------------------------------------------
/src/appUtil/tsestraverse.ts:
--------------------------------------------------------------------------------
1 | const estraverse = require('estraverse-jsx')
2 |
3 | const traverser = async (ast:any) =>{
4 | try {
5 | let cache:{[key:string]: object} = {}
6 |
7 | await estraverse.traverse(ast, {
8 | enter:function(node:any, parent:any){
9 | if(node.type=='VariableDeclaration'){
10 | return estraverse.VisitorOption.skip;
11 | }
12 | },
13 | leave: function (node:any, parent:any) {
14 | if (node.type == 'Property') {
15 | // console.log(node);
16 | cache[node.key.name] = {
17 | value: node.value.value,
18 | start: node.loc.start.line,
19 | end: node.loc.end.line,
20 | }
21 | }
22 | },
23 | keys:{
24 | 'ClassProperty': ['key', 'value'],
25 | 'TSModuleDeclaration': ['body'],
26 | 'TSModuleBlock': ['body']
27 | },
28 | fallback: 'iteration'
29 | });
30 | return cache;
31 | } catch (e) {
32 | console.log('Traverse Error: ', e);
33 | }
34 | }
35 |
36 | export default traverser
--------------------------------------------------------------------------------
/src/appUtil/tsmorph.ts:
--------------------------------------------------------------------------------
1 | import {Project, Node } from 'ts-morph'
2 |
3 | const tsmorph = async (path: string, property:string, value:any) =>{
4 | const project = new Project();
5 | const sourceFile = project.addSourceFileAtPath(path);
6 |
7 | sourceFile.forEachDescendant(node=>{
8 | if(Node.isPropertyAssignment(node)){
9 | if(node.getName() === `${property}`){
10 | node.replaceWithText(`${property}: ${value}`)
11 | }
12 | }
13 | })
14 |
15 | await sourceFile.save()
16 | await project.save()
17 | }
18 |
19 | export default tsmorph
--------------------------------------------------------------------------------
/src/appUtil/versionFinder.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | const versionFinder = (obj:any) =>{
4 | let version = 0;
5 | // Rather than using loops to locate electron version, I think hard-coding might be faster here, since this is O(1)
6 |
7 | if(obj.devDependencies && obj.devDependencies.electron){
8 | let tempLiteral = obj.devDependencies.electron.replace('^', '').split(".")
9 | tempLiteral.pop();
10 | version = Number(tempLiteral.join('.'))
11 | }else if (obj.dependencies && obj.dependencies.electron){
12 | let tempLiteral = obj.dependencies.electron.replace('^', '').split(".")
13 | tempLiteral.pop();
14 | version = Number(tempLiteral.join('.'))
15 | }
16 | return version;
17 | }
18 |
19 | export default versionFinder
--------------------------------------------------------------------------------
/src/icons/Clipboard01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/FaradayJS/e28e2171d90103732cd5140b2d42b1fb38e48e9f/src/icons/Clipboard01.jpg
--------------------------------------------------------------------------------
/src/icons/Clipboard02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/FaradayJS/e28e2171d90103732cd5140b2d42b1fb38e48e9f/src/icons/Clipboard02.jpg
--------------------------------------------------------------------------------
/src/icons/Clipboard03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/FaradayJS/e28e2171d90103732cd5140b2d42b1fb38e48e9f/src/icons/Clipboard03.jpg
--------------------------------------------------------------------------------
/src/icons/Clipboard04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/FaradayJS/e28e2171d90103732cd5140b2d42b1fb38e48e9f/src/icons/Clipboard04.jpg
--------------------------------------------------------------------------------
/src/icons/GitHub-Mark-64px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/FaradayJS/e28e2171d90103732cd5140b2d42b1fb38e48e9f/src/icons/GitHub-Mark-64px.png
--------------------------------------------------------------------------------
/src/icons/deleteIcon.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/icons/faraday-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/FaradayJS/e28e2171d90103732cd5140b2d42b1fb38e48e9f/src/icons/faraday-logo.png
--------------------------------------------------------------------------------
/src/icons/google-docs.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/openFolder.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/icons/testing.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { app, BrowserWindow, ipcMain, dialog, Menu } from 'electron';
2 | import installExtension, { REDUX_DEVTOOLS, REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer';
3 | import { parser, htmlparser } from './appUtil/parser'
4 | import checker from './appUtil/checker'
5 | import traverser from './appUtil/tsestraverse';
6 | import versionFinder from './appUtil/versionFinder';
7 | import menuTemplate from './appUtil/menuTemplate';
8 | import tsmorph from './appUtil/tsmorph';
9 | import OpenFolder from './appUtil/openFolder';
10 | import {doInclude, doNotInclude} from './appUtil/ignoreArr'
11 |
12 | const fs = require('fs')
13 | const path = require('path')
14 | const isDev = require('electron-is-dev')
15 |
16 | let win: BrowserWindow;
17 |
18 | const options = {
19 | width: 800,
20 | height: 600,
21 | webPreferences: {
22 | nodeIntegration: false,
23 | preload: path.join(__dirname, "preload.js")
24 | }
25 | }
26 |
27 | const createWindow = (): void => {
28 | win = new BrowserWindow(options
29 | );
30 |
31 | //Both methods work
32 | win.loadFile(path.join(__dirname, './index.html'));
33 | //win.loadURL(`file://${path.join(__dirname, "index.html")}`)
34 |
35 |
36 | ipcMain.on('main:open-file', async (event, payload)=>{
37 | try{
38 | const result = await OpenFile();
39 | event.reply('preload:open-file', result)
40 | }catch(err){
41 | console.log(err)
42 | }
43 | })
44 |
45 | ipcMain.on('main:change-value', async(event, payload)=>{
46 | tsmorph(payload[0]+payload[1], payload[2], payload[3])
47 | })
48 |
49 | ipcMain.on('main:open-folder', async (event, payload)=>{
50 | try{
51 | const rawResult: any = await OpenFolder(win, doInclude,doNotInclude);
52 | let processedResult;
53 | if(rawResult) processedResult = await processCodeBase(rawResult);
54 | event.sender.send('preload:open-folder', processedResult);
55 | } catch (e) {
56 | console.log('Open Folder Error: ', e);
57 | }
58 | })
59 |
60 | ipcMain.on('main:refresh-code', async (event, payload)=>{
61 | try{
62 | let refreshedObj = await refreshCode(payload[0]+payload[1], payload[2]);
63 | event.sender.send('preload:refreshed-obj', refreshedObj)
64 | }catch(e){
65 | console.log('Refresh Error ', e)
66 | }
67 | })
68 |
69 | ipcMain.on('main:addIgnore', async(event, payload:string[])=>{
70 | payload.forEach(x=>{
71 | if(!doNotInclude.includes(x) && x !== undefined){
72 | doNotInclude.push(x)
73 | }
74 | })
75 | })
76 |
77 | ipcMain.on('main:removeIgnore', async(event, payload:string)=>{
78 | const index = doNotInclude.indexOf(payload);
79 | doNotInclude.splice(index, 1);
80 | })
81 |
82 |
83 | const isMac = process.platform === 'darwin'
84 | const template: any = menuTemplate(win);
85 | const menu = Menu.buildFromTemplate(template);
86 | Menu.setApplicationMenu(menu);
87 | }
88 |
89 | app.on('ready', createWindow);
90 |
91 | // Open File Function
92 | const OpenFile = async () => {
93 | // Opens file dialog looking for markdown extension
94 | const files: Promise | Boolean | String = dialog.showOpenDialog(win, {
95 | properties: ['openFile', 'multiSelections'],
96 | })
97 |
98 | // If no files
99 | if (!files) return;
100 |
101 | const file = await files; // Grabbing first item in the array. files(dialog.showOpenDialog) returns the absoulte path to the selected file
102 | if (file) { // !! ensures the resulting type is a boolean
103 | //console.log(file)
104 | };
105 |
106 | }
107 |
108 | const reOrderTests = async (resultsArr: any) => {
109 | const reorderedTests: Array = [];
110 | for(let i = 0; i < resultsArr.length; i++){
111 | if(resultsArr[i].fileResults["status"] == "fail" || resultsArr[i].fileResults["status"] == "fail by default") {
112 | reorderedTests.push(resultsArr[i]);
113 | }
114 | }
115 | for(let i = 0; i < resultsArr.length; i++){
116 | if(resultsArr[i].fileResults["status"] == "pass" || resultsArr[i].fileResults["status"] == "pass by default") {
117 | reorderedTests.push(resultsArr[i]);
118 | }
119 | }
120 | return reorderedTests;
121 | }
122 |
123 | const processCodeBase = async (codebaseObj:any) => {
124 | try {
125 | let version = 13;
126 | if(codebaseObj.packageJsonContents){
127 | version = await versionFinder(JSON.parse(codebaseObj.packageJsonContents))
128 | }
129 | let rawTestResults: any[] = [];
130 | let traversedAstNodes: any = {};
131 |
132 | const addFileNamesToResultsArray: any = (resultsArray: any, file: number) => {
133 | resultsArray.forEach((resultObj: any) => {
134 | rawTestResults.push({
135 | fileResults: resultObj,
136 | fileName: codebaseObj.fileObjectArray[file].fileName,
137 | filePath: codebaseObj.fileObjectArray[file].path
138 | });
139 | });
140 | }
141 |
142 | for (let i = 0; i < codebaseObj.fileObjectArray.length; i++) {
143 | if(codebaseObj.fileObjectArray[i].fileName.includes('.html')){
144 | const htmlFileResultsArray: any = await htmlparser(codebaseObj.fileObjectArray[i].contents);
145 | addFileNamesToResultsArray(htmlFileResultsArray, i);
146 | }else{
147 | const ast: any = await parser(codebaseObj.fileObjectArray[i].contents);
148 | traversedAstNodes = await traverser(ast);
149 | if(traversedAstNodes.hasOwnProperty('webPreferences')){
150 | const fileResultsArray: any = checker(traversedAstNodes, version);
151 | addFileNamesToResultsArray(fileResultsArray, i);
152 | }
153 | }
154 | }
155 |
156 | const reorderedTests: any = await reOrderTests(rawTestResults);
157 | return reorderedTests;
158 | }catch(err){
159 | console.log('ProcessCodeBase: ', err)
160 | }
161 | }
162 |
163 | const refreshCode = async (path:string, passedTestProp:string) => {
164 | let version = 13;
165 | const fileContent = await fs.readFileSync(path).toString();
166 | const ast:any = await parser(fileContent);
167 | let traversedAstNodes = await traverser(ast);
168 | const fileResultsArray: any = await checker([traversedAstNodes], version);
169 | for(let i = 0; i{
7 | ipcRenderer.send('main:open-file')
8 | },
9 | openFolder: ()=>{
10 | ipcRenderer.send('main:open-folder')
11 | },
12 | receiveData: (channel:any, func:any) =>{
13 | let validChannels = ['preload:open-folder', 'preload:refreshed-obj'];
14 | if(validChannels.includes(channel)){
15 | ipcRenderer.once(channel, (event, ...args)=>func(...args))
16 | }
17 | },
18 | changeValue: (args:any) =>{
19 | ipcRenderer.send('main:change-value', args)
20 | },
21 | refreshCode: (args:any) =>{
22 | ipcRenderer.send('main:refresh-code', args)
23 | },
24 | addIgnore:(args:any)=>{
25 | ipcRenderer.send('main:addIgnore', args)
26 | },
27 | removeIgnore:(args:string)=>{
28 | ipcRenderer.send('main:removeIgnore', args)
29 | }
30 | }
31 | )
32 |
--------------------------------------------------------------------------------
/src/renderer/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import '../../src/styles.css';
3 | import NavBar from './components/NavBar';
4 |
5 | const App = () => {
6 |
7 | return (
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default App;
--------------------------------------------------------------------------------
/src/renderer/Slices/ignoreItemsSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit';
2 | import {TestResultState} from './testResultSlice'
3 |
4 | interface Ostate{
5 | testresult: TestResultState,
6 | ignoreItems: IState
7 | }
8 |
9 | interface IState{
10 | textInput:string,
11 | ignoreArr: string[]
12 | }
13 |
14 | interface addIgnoreState{
15 | payload: string;
16 | type: string;
17 | }
18 |
19 |
20 | export const ignoreItems = createSlice({
21 | name: 'ignoreItems',
22 | initialState:{
23 | textInput: '',
24 | ignoreArr: []
25 | },
26 | reducers:{
27 | setReduxTextInput: (state, action) =>{
28 | state.textInput = action.payload;
29 | },
30 | removeReduxTextInput: (state)=>{
31 | state.textInput = '';
32 | },
33 | addIgnoreArr: (state:IState, action:addIgnoreState) =>{
34 | state.ignoreArr = [...state.ignoreArr, action.payload]
35 | },
36 | removeIgnoreArr: (state:IState, action:addIgnoreState)=>{
37 | let tempArr = [...state.ignoreArr];
38 | const index = tempArr.indexOf(action.payload);
39 | tempArr.splice(index, 1); // Remove 1 element at index
40 | state.ignoreArr = tempArr;
41 | }
42 | }
43 |
44 | })
45 |
46 | export const { setReduxTextInput, removeReduxTextInput, addIgnoreArr, removeIgnoreArr } = ignoreItems.actions;
47 | export default ignoreItems.reducer;
48 | export const ignoreItemsState = (state:Ostate) => state.ignoreItems;
--------------------------------------------------------------------------------
/src/renderer/Slices/loadingSlice.tsx:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2 |
3 | const initialState={gettingData: true}
4 |
5 |
6 | const loadingSlice = createSlice({
7 | name: 'loading',
8 | initialState,
9 | reducers: {
10 |
11 | updateLoading(state){
12 | state.gettingData=!state.gettingData
13 | },
14 | },
15 | });
16 |
17 | export const { updateLoading} = loadingSlice.actions;
18 | export default loadingSlice.reducer;
--------------------------------------------------------------------------------
/src/renderer/Slices/testResultSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2 | import {updateLoading} from'./loadingSlice'
3 |
4 | interface fileResult {
5 | start: number
6 | status: string
7 | end: number
8 | testProp: string
9 | description: string
10 | failValue: boolean
11 | }
12 |
13 | interface testResult {
14 | fileName: string,
15 | filePath: string,
16 | fileResults: fileResult
17 | }
18 |
19 | export interface TestResultState {
20 | projectName: string,
21 | testResults: testResult[],
22 | expansionStatus: boolean[],
23 | fixedStatus: boolean[],
24 | morphBools: boolean[],
25 | simpleBool: boolean,
26 | }
27 |
28 | const initialState = {
29 | projectName: '',
30 | testResults: [],
31 | expansionStatus: [],
32 | fixedStatus: [],
33 | morphBools: [],
34 | simpleBool: false,
35 | } as TestResultState;
36 |
37 | const testResultSlice = createSlice({
38 | name: 'testresult',
39 | initialState,
40 | reducers: {
41 | // resetResults(state){state.testResults=[]},
42 |
43 | newTestResults(state, action: PayloadAction) {
44 | console.log('payload: ',action.payload);
45 | state.testResults = action.payload;
46 | // console.log(state.testResults);
47 | for (let i = 0; i < state.testResults.length; i += 1) {
48 | state.expansionStatus.push(false);
49 | state.fixedStatus.push(false)
50 | }
51 | },
52 | expandResult(state, action: PayloadAction) {
53 | state.expansionStatus[action.payload] = !state.expansionStatus[action.payload];
54 | },
55 | updateResult(state, action: PayloadAction) {
56 | // console.log('action.payload: ',action.payload)
57 | state.fixedStatus[action.payload] = true
58 | },
59 | },
60 | });
61 |
62 | export const { newTestResults, expandResult, updateResult} = testResultSlice.actions;
63 | export default testResultSlice.reducer;
--------------------------------------------------------------------------------
/src/renderer/components/IgnoreCards.tsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect} from 'react';
2 | import { useSelector, useDispatch } from 'react-redux';
3 | import { ignoreItemsState, removeIgnoreArr } from '../Slices/ignoreItemsSlice';
4 | import deleteIcon from '../../icons/deleteIcon.svg';
5 |
6 | const IgnoreCards = (props:any) => {
7 | const state = useSelector(ignoreItemsState)
8 | const dispatch = useDispatch();
9 |
10 | const handleDelete = (x:string)=>{
11 | dispatch(removeIgnoreArr(x))
12 | //@ts-expect-error
13 | bridgeAPI.removeIgnore(x);
14 | }
15 |
16 | useEffect(()=>{
17 | //@ts-expect-error
18 | bridgeAPI.addIgnore(state.ignoreArr);
19 | }, [state.ignoreArr])
20 |
21 | const renderArr = state.ignoreArr.map(x=>{
22 | return(
23 |
24 |
25 | {x}
26 |
27 | {/* className="border border-transparent pl-4 pr-4 hover:bg-blueGray-500 hover:border-white" */}
28 |
handleDelete(x)}>
29 |
30 |
31 |
32 | )})
33 |
34 | return(
35 |
36 | {renderArr}
37 |
38 | )
39 | }
40 |
41 | export default IgnoreCards
--------------------------------------------------------------------------------
/src/renderer/components/Loader.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Loader = () => {
4 | // let circleCommonClasses = 'h-2.5 w-2.5 bg-current rounded-full';
5 |
6 | return (
7 |
10 | );
11 | };
12 |
13 | export default Loader;
--------------------------------------------------------------------------------
/src/renderer/components/NavBar.tsx:
--------------------------------------------------------------------------------
1 | import React, {useState, useEffect} from 'react';
2 | import { useSelector, useDispatch } from 'react-redux';
3 | import openFolderIcon from '../../icons/openFolder.svg';
4 | import icon from '../../icons/iconTransparent.svg';
5 | import ResultDisplay from './ResultDisplay'
6 | import { RootState } from '../store';
7 | import { newTestResults } from '../Slices/testResultSlice';
8 | import IgnoreCards from './IgnoreCards'
9 | import { setReduxTextInput, removeReduxTextInput, addIgnoreArr, ignoreItemsState } from '../Slices/ignoreItemsSlice';
10 | import { updateLoading } from '../Slices/loadingSlice';
11 |
12 |
13 | const NavBar: () => JSX.Element = () => {
14 | const [textInput, setTextInput] = useState('');
15 |
16 | const state = useSelector(ignoreItemsState)
17 | const name = useSelector((state: RootState) => state.testResults.projectName);
18 | const loading = useSelector((state: RootState) => state.loading);
19 | const dispatch = useDispatch();
20 |
21 | const handleClickOpenFolder = () => {
22 | // dispatch(resetResults())
23 | // console.log('laoding: ',loading)
24 | dispatch(updateLoading())
25 | //@ts-expect-error
26 | bridgeAPI.openFolder();
27 |
28 | //@ts-expect-error
29 | bridgeAPI.receiveData('preload:open-folder', (data: any)=>{
30 | // dispatch(updateLoading())
31 | // console.log('data: ', data);
32 | dispatch(newTestResults(data));
33 | });
34 | }
35 |
36 | const handleSubmit = (e: React.MouseEvent) =>{
37 | e.preventDefault();
38 | dispatch(setReduxTextInput(textInput));
39 | dispatch(addIgnoreArr(textInput));
40 | setTextInput('')
41 | dispatch(removeReduxTextInput());
42 | }
43 |
44 | useEffect(()=>{
45 | //console.log(state.ignoreArr);
46 |
47 | //@ts-expect-error
48 | bridgeAPI.addIgnore(state.ignoreArr);
49 |
50 | }, [state.ignoreArr])
51 |
52 | return(
53 |
54 |
55 | {/* flex flex-col rounded overflow-auto h-auto border border-transparent border-shadow shadow-lg p-3 hover:bg-blueGray-500 hover:border-gray-darkest */}
56 |
57 |
58 | Run Tests
59 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | );
72 | }
73 |
74 | export default NavBar;
--------------------------------------------------------------------------------
/src/renderer/components/ResultDisplay.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 |
3 | import { RootState } from '../store';
4 | import { useSelector, useDispatch } from 'react-redux';
5 | import { expandResult, updateResult } from '../Slices/testResultSlice';
6 | import Loader from './Loader'
7 | import { updateLoading } from '../Slices/loadingSlice';
8 |
9 | interface fileResult{
10 | start: number
11 | status: string
12 | end: number
13 | testProp: string
14 | description: string
15 | failValue: boolean
16 | }
17 |
18 | const ResultDisplay = (): JSX.Element => {
19 | const newData = useSelector((state: RootState) => state.testResults.testResults);
20 | const expandBools = useSelector((state: RootState) => state.testResults.expansionStatus);
21 | const fixedBools = useSelector((state: RootState) => state.testResults.fixedStatus);
22 | const loading = useSelector((state: RootState) => state.loading.gettingData);
23 | const dispatch = useDispatch();
24 | console.log('Expandbools: ', expandBools);
25 |
26 | const handleClickChangeValue = async (args:[string, string, string, boolean, number, string])=>{
27 | //@ts-expect-error
28 | bridgeAPI.changeValue(args);
29 |
30 | //@ts-expect-error
31 | bridgeAPI.refreshCode(args);
32 |
33 | //@ts-expect-error
34 | bridgeAPI.receiveData('preload:refreshed-obj', (data: any)=>{
35 | // if(data.status.includes('pass')) console.log(data);
36 | // data['id']=args[4]
37 | if(data.status.includes('pass')){
38 | dispatch(updateResult(args[4]));
39 | dispatch(expandResult(args[4]))
40 | }
41 | // conditional[args[4]]=data
42 | });
43 | }
44 |
45 | useEffect(()=>{
46 | dispatch(updateLoading())
47 |
48 | },[newData])
49 |
50 | const conditional: Array = [];
51 |
52 | // let failCount: any = 0;
53 | // for(let i = 0; i < newData.length; i++){
54 | // if(newData[i].fileResults["status"] == "fail" || newData[i].fileResults["status"] == "fail by default") failCount++;
55 | // }
56 |
57 | // if(failCount > 0) conditional.push(
58 | //
59 | //
60 | // Fails:
61 | // {failCount}
62 | //
63 | //
64 | // );
65 |
66 | if(newData){
67 | for (let i = 0; i < newData.length; i++) {
68 | const fileName:string = newData[i].fileName;
69 | const filePath:string = newData[i].filePath;
70 | const {start, status, end, testProp, failValue, description}:fileResult = newData[i].fileResults;
71 |
72 | conditional.push(
73 |
74 |
dispatch(expandResult(i))} className="flex flex-col rounded overflow-auto h-auto border border-transparent border-shadow shadow-lg p-3 hover:bg-blueGray-500 hover:border-gray-darkest">
75 |
76 | Test: {testProp}
77 |
78 | {status.includes('pass') &&
79 |
80 | Status: {status}
81 |
82 | }
83 | {(!status.includes('pass')&&!fixedBools[i])&&
84 |
85 | Status: {status}
86 |
}
87 | {fixedBools[i]&&
88 | Status: pass
89 |
}
90 | {(status.includes('fail')&&!fixedBools[i]) &&
91 |
92 | Issue: {`${testProp} is set to ${failValue}`}
93 |
}
94 |
95 | File Name: {fileName}
96 |
97 | {(start>0&&!fixedBools[i]) && Line Number: {start}
}
98 | {/* {end>0 && End Line: {end}
} */}
99 |
100 | File Path: {filePath}
101 |
102 |
103 | {fixedBools[i] &&
104 |
105 |
106 |
107 |
108 |
The setting has been changed
109 |
The previous setting was {`${failValue}`} .
110 |
111 |
112 |
}
113 |
114 |
115 |
116 |
117 |
118 |
119 | {expandBools[i] &&
120 | Details: {description}
121 | {!testProp.includes('needToUpdateVersion') && status.includes('fail') && handleClickChangeValue([filePath, fileName, testProp, !failValue, i, description])}>
123 | Change the setting
124 | }
125 |
126 |
}
127 |
);
128 | }}
129 |
130 | return (
131 |
132 |
133 | {loading && }
134 | {!loading&&conditional}
135 |
136 |
137 | );
138 | };
139 |
140 | export default ResultDisplay;
141 |
--------------------------------------------------------------------------------
/src/renderer/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import '../../src/styles.css';
4 | import App from './App';
5 | import { Provider } from 'react-redux';
6 | import { store } from './store';
7 |
8 | ReactDOM.render(
9 |
10 |
15 |
16 | ,
17 | document.getElementById('root')
18 | );
--------------------------------------------------------------------------------
/src/renderer/store.ts:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit';
2 | import { combineReducers, createStore } from 'redux';
3 | //import { composeWithDevTools } from 'redux-devtools-extension';
4 | import testResultsReducer from './Slices/testResultSlice'
5 | import ignoreItemsSlice from './Slices/ignoreItemsSlice';
6 | import loadingReducer from './Slices/loadingSlice'
7 |
8 | export const store = configureStore({
9 | reducer: {
10 | testResults: testResultsReducer,
11 | ignoreItems: ignoreItemsSlice,
12 | loading: loadingReducer,
13 | },
14 |
15 | });
16 |
17 | //const reducer = combineReducers({ testResults: testResultsReducer });
18 | //export const store = createStore(reducer);
19 |
20 | export type RootState = ReturnType
21 | export type AppDispatch = typeof store.dispatch
22 |
23 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 |
3 | @tailwind components;
4 |
5 | @tailwind utilities;
6 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const colors = require('tailwindcss/colors')
2 | module.exports = {
3 | // mode: 'jit',
4 | purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
5 | darkMode: false, // or 'media' or 'class'
6 | theme: {
7 | extend: {},
8 | colors: {
9 | transparent: 'transparent',
10 | current: 'currentColor',
11 | gray: {
12 | other: '#89898b',
13 | other2: '#1b1c1c',
14 | light: '#b0b0b1',
15 | DEFAULT: '#3a3b3d',
16 | medium: '#333333',
17 | dark: '#28292a',
18 | darkest: '#0f1010'
19 | },
20 | blue: {
21 | light: '#e1edf3',
22 | DEFUALT: '#9dc6d8',
23 | dark: '#4e636c'
24 | },
25 | peach: {
26 | light: '#fef3ef',
27 | DEFUALT: '#fac3af',
28 | dark: '#7d6157',
29 | other: '#af897a'
30 | },
31 | teal: {
32 | light: '#E6FFFA',
33 | DEFUALT: '#38B2AC',
34 | dark: '#38B2AC',
35 | },
36 | },
37 | screens: {
38 | sm: '480px',
39 | md: '768px',
40 | lg: '976px',
41 | xl: '1440px',
42 | },
43 | container: {
44 | center: true,
45 | padding: {
46 | DEFAULT: '1rem',
47 | sm: '2rem',
48 | lg: '4rem',
49 | xl: '5rem',
50 | '2xl': '6rem'
51 | },
52 | },
53 | fontFamily: {
54 | sans: ['Graphik', 'sans-serif'],
55 | serif: ['Merriweather', 'serif'],
56 | }
57 | },
58 | variants: {
59 | extend: {},
60 | },
61 | plugins: [],
62 | }
63 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Basic Options */
6 | // "incremental": true, /* Enable incremental compilation */
7 | "target": "ES2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
9 | "lib": ["es2017", "dom"], /* Specify library files to be included in the compilation. */
10 | // "allowJs": true, /* Allow javascript files to be compiled. */
11 | // "checkJs": true, /* Report errors in .js files. */
12 | "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
15 | // "sourceMap": true, /* Generates corresponding '.map' file. */
16 | // "outFile": "./", /* Concatenate and emit output to single file. */
17 | "outDir": "./dist", /* Redirect output structure to the directory. */
18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
19 | // "composite": true, /* Enable project compilation */
20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
21 | // "removeComments": true, /* Do not emit comments to output. */
22 | // "noEmit": true, /* Do not emit outputs. */
23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
26 |
27 | /* Strict Type-Checking Options */
28 | "strict": true, /* Enable all strict type-checking options. */
29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
30 | // "strictNullChecks": true, /* Enable strict null checks. */
31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
36 |
37 | /* Additional Checks */
38 | // "noUnusedLocals": true, /* Report errors on unused locals. */
39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
43 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
44 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
45 |
46 | /* Module Resolution Options */
47 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
48 | "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
49 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
50 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
51 | // "typeRoots": [], /* List of folders to include type definitions from. */
52 | // "types": [], /* Type declaration files to be included in compilation. */
53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
54 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
56 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
57 | "resolveJsonModule": true,
58 | /* Source Map Options */
59 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
61 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
62 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
63 |
64 | /* Experimental Options */
65 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
66 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
67 |
68 | /* Advanced Options */
69 | "skipLibCheck": true, /* Skip type checking of declaration files. */
70 | "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
71 | "paths": {
72 | "@/*": [
73 | "src/*"
74 | ]
75 | }
76 | },
77 | }
78 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const electronConfigs = require('./webpack.electron.js');
2 | const reactConfigs = require('./webpack.react.js');
3 |
4 | module.exports = [
5 | electronConfigs,
6 | reactConfigs,
7 | ];
--------------------------------------------------------------------------------
/webpack.electron.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | // Build Mode
5 | mode: "development",
6 | // Electron Entrypoint
7 | entry: './src/main.ts',
8 | target: 'electron-main',
9 | resolve: {
10 | alias: {
11 | ['@']: path.resolve(__dirname, 'src')
12 | },
13 | extensions: ['.tsx', '.ts', '.js', 'jsx'],
14 | },
15 | module: {
16 | rules: [{
17 | // "test" is commonly used to match the file extension
18 | test: /\.(js(x?)|ts(x?))$/,
19 | // include all modules matching these conditions (/src folder)
20 | exclude: /node_modules/,
21 | // "exclude" should be used to exclude exceptions
22 | // try to prefer "include" when possible
23 |
24 | // the "loader"
25 | use: [{ loader: 'ts-loader' }]
26 | }]
27 | },
28 | output: {
29 | path: path.resolve(__dirname, 'dist'),
30 | filename: 'main.js'
31 | },
32 | }
--------------------------------------------------------------------------------
/webpack.react.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin');
2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
3 | const path = require('path');
4 |
5 | module.exports = {
6 | mode: "development",
7 | entry: './src/renderer/index.tsx',
8 | target: 'electron-renderer',
9 | devtool: 'source-map',
10 | devServer: {
11 | contentBase: path.join(__dirname, 'dist/renderer/index.js'),
12 | compress: true,
13 | hot: true,
14 | port: 8080,
15 | },
16 | resolve: {
17 | alias: {
18 | ['@']: path.resolve(__dirname, 'src')
19 | },
20 | extensions: ['.tsx', '.ts', '.js', '.jsx'],
21 | },
22 | module: {
23 | rules: [
24 | {
25 | test: /\.(js(x?)|ts(x?))$/,
26 | include: /src/,
27 | use: [{ loader: 'ts-loader' }]
28 | },
29 | {
30 | test: /.(js|jsx)$/,
31 | include: /src/,
32 | loader: 'babel-loader',
33 | options: {
34 | presets: ['@babel/preset-env', '@babel/preset-react'],
35 | },
36 | },
37 | {
38 | test: /\.css$/,
39 | use: [
40 | MiniCssExtractPlugin.loader,
41 | "css-loader", "postcss-loader",
42 | ],
43 | },
44 | {
45 | test: /\.svg$/,
46 | use: [
47 | {
48 | loader: 'svg-url-loader',
49 | options: {
50 | limit: 10000,
51 | },
52 | },
53 | ],
54 | },
55 | ]
56 | },
57 | output: {
58 | path: __dirname + '/dist/renderer',
59 | filename: 'index.js'
60 | },
61 | devServer: {
62 | /*The bundled files will be available in the browser under this path.
63 | publicPath says that any request made to '/' will be served the development version of our bundle via localhost:8080. publicPath should match where we have index.html
64 | */
65 | publicPath: '/dist',
66 |
67 | hot: true,
68 | // Tell the server where to serve content from.
69 | contentBase: path.resolve(__dirname, './dist'),
70 | watchContentBase: true,
71 |
72 | // Proxy says taht any request made to '/api' will be routed to our server on localhost:3000
73 | // proxy should match whatever is going to match your fetch request on your frontend.
74 | },
75 | plugins: [
76 | new HtmlWebpackPlugin({
77 | template: './index.html',
78 | filename: path.join(__dirname, "./dist/index.html")
79 | }),
80 | new MiniCssExtractPlugin({
81 | filename: "styles.css",
82 | chunkFilename: path.join(__dirname, "./dist/src/styles.css")
83 | })
84 | ]
85 | };
--------------------------------------------------------------------------------