diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-01-09 22:16:29 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-01-09 22:17:26 +0100 |
commit | fb7118ff1c8f0dcd61f15e51b193512283d83fa1 (patch) | |
tree | 721cee6a64b44a56b7f05f39750a65cda5fb4ef6 /packages/main/src | |
parent | build: Add eslint-plugin-jest (diff) | |
download | sophie-fb7118ff1c8f0dcd61f15e51b193512283d83fa1.tar.gz sophie-fb7118ff1c8f0dcd61f15e51b193512283d83fa1.tar.zst sophie-fb7118ff1c8f0dcd61f15e51b193512283d83fa1.zip |
build: Add eslint-plugin-unicorn
Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/main/src')
-rw-r--r-- | packages/main/src/controllers/__tests__/initConfig.spec.ts | 2 | ||||
-rw-r--r-- | packages/main/src/controllers/initConfig.ts | 14 | ||||
-rw-r--r-- | packages/main/src/devTools.ts | 3 | ||||
-rw-r--r-- | packages/main/src/index.ts | 72 | ||||
-rw-r--r-- | packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts | 24 | ||||
-rw-r--r-- | packages/main/src/stores/Config.ts | 9 | ||||
-rw-r--r-- | packages/main/src/utils/log.ts | 5 |
7 files changed, 68 insertions, 61 deletions
diff --git a/packages/main/src/controllers/__tests__/initConfig.spec.ts b/packages/main/src/controllers/__tests__/initConfig.spec.ts index 9a5f85e..11e7690 100644 --- a/packages/main/src/controllers/__tests__/initConfig.spec.ts +++ b/packages/main/src/controllers/__tests__/initConfig.spec.ts | |||
@@ -133,7 +133,7 @@ describe('when it has loaded the config', () => { | |||
133 | }); | 133 | }); |
134 | 134 | ||
135 | it('should throttle saving changes to the config file', () => { | 135 | it('should throttle saving changes to the config file', () => { |
136 | mocked(persistenceService.writeConfig).mockResolvedValue(undefined); | 136 | mocked(persistenceService.writeConfig).mockResolvedValue(); |
137 | config.setThemeSource('dark'); | 137 | config.setThemeSource('dark'); |
138 | jest.advanceTimersByTime(lessThanThrottleMs); | 138 | jest.advanceTimersByTime(lessThanThrottleMs); |
139 | config.setThemeSource('light'); | 139 | config.setThemeSource('light'); |
diff --git a/packages/main/src/controllers/initConfig.ts b/packages/main/src/controllers/initConfig.ts index e83b8da..915f451 100644 --- a/packages/main/src/controllers/initConfig.ts +++ b/packages/main/src/controllers/initConfig.ts | |||
@@ -38,7 +38,7 @@ export default async function initConfig( | |||
38 | ): Promise<Disposer> { | 38 | ): Promise<Disposer> { |
39 | log.trace('Initializing config controller'); | 39 | log.trace('Initializing config controller'); |
40 | 40 | ||
41 | let lastSnapshotOnDisk: ConfigSnapshotOut | null = null; | 41 | let lastSnapshotOnDisk: ConfigSnapshotOut | undefined; |
42 | 42 | ||
43 | async function readConfig(): Promise<boolean> { | 43 | async function readConfig(): Promise<boolean> { |
44 | const result = await persistenceService.readConfig(); | 44 | const result = await persistenceService.readConfig(); |
@@ -46,8 +46,8 @@ export default async function initConfig( | |||
46 | try { | 46 | try { |
47 | applySnapshot(config, result.data); | 47 | applySnapshot(config, result.data); |
48 | lastSnapshotOnDisk = getSnapshot(config); | 48 | lastSnapshotOnDisk = getSnapshot(config); |
49 | } catch (err) { | 49 | } catch (error) { |
50 | log.error('Failed to apply config snapshot', result.data, err); | 50 | log.error('Failed to apply config snapshot', result.data, error); |
51 | } | 51 | } |
52 | } | 52 | } |
53 | return result.found; | 53 | return result.found; |
@@ -70,8 +70,8 @@ export default async function initConfig( | |||
70 | debounce((snapshot) => { | 70 | debounce((snapshot) => { |
71 | // We can compare snapshots by reference, since it is only recreated on store changes. | 71 | // We can compare snapshots by reference, since it is only recreated on store changes. |
72 | if (lastSnapshotOnDisk !== snapshot) { | 72 | if (lastSnapshotOnDisk !== snapshot) { |
73 | writeConfig().catch((err) => { | 73 | writeConfig().catch((error) => { |
74 | log.error('Failed to write config on config change', err); | 74 | log.error('Failed to write config on config change', error); |
75 | }); | 75 | }); |
76 | } | 76 | } |
77 | }, debounceTime), | 77 | }, debounceTime), |
@@ -80,8 +80,8 @@ export default async function initConfig( | |||
80 | const disposeWatcher = persistenceService.watchConfig(async () => { | 80 | const disposeWatcher = persistenceService.watchConfig(async () => { |
81 | try { | 81 | try { |
82 | await readConfig(); | 82 | await readConfig(); |
83 | } catch (err) { | 83 | } catch (error) { |
84 | log.error('Failed to read config', err); | 84 | log.error('Failed to read config', error); |
85 | } | 85 | } |
86 | }, debounceTime); | 86 | }, debounceTime); |
87 | 87 | ||
diff --git a/packages/main/src/devTools.ts b/packages/main/src/devTools.ts index 69f1514..4ca1bf3 100644 --- a/packages/main/src/devTools.ts +++ b/packages/main/src/devTools.ts | |||
@@ -49,7 +49,8 @@ export async function installDevToolsExtensions(): Promise<void> { | |||
49 | /* eslint-disable-next-line | 49 | /* eslint-disable-next-line |
50 | import/no-extraneous-dependencies, | 50 | import/no-extraneous-dependencies, |
51 | global-require, | 51 | global-require, |
52 | @typescript-eslint/no-var-requires | 52 | @typescript-eslint/no-var-requires, |
53 | unicorn/prefer-module | ||
53 | */ | 54 | */ |
54 | } = require('electron-devtools-installer') as typeof import('electron-devtools-installer'); | 55 | } = require('electron-devtools-installer') as typeof import('electron-devtools-installer'); |
55 | await installExtension([REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS], { | 56 | await installExtension([REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS], { |
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index 1f80e44..02e6cda 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts | |||
@@ -19,9 +19,9 @@ | |||
19 | * SPDX-License-Identifier: AGPL-3.0-only | 19 | * SPDX-License-Identifier: AGPL-3.0-only |
20 | */ | 20 | */ |
21 | 21 | ||
22 | import { arch } from 'os'; | 22 | import { arch } from 'node:os'; |
23 | import { join } from 'path'; | 23 | import path from 'node:path'; |
24 | import { URL } from 'url'; | 24 | import { URL } from 'node:url'; |
25 | 25 | ||
26 | import { | 26 | import { |
27 | ServiceToMainIpcMessage, | 27 | ServiceToMainIpcMessage, |
@@ -101,11 +101,14 @@ app.setAboutPanelOptions({ | |||
101 | version: '', | 101 | version: '', |
102 | }); | 102 | }); |
103 | 103 | ||
104 | // eslint-disable-next-line unicorn/prefer-module -- Electron apps run in a commonjs environment. | ||
105 | const thisDir = __dirname; | ||
106 | |||
104 | function getResourcePath(relativePath: string): string { | 107 | function getResourcePath(relativePath: string): string { |
105 | return join(__dirname, relativePath); | 108 | return path.join(thisDir, relativePath); |
106 | } | 109 | } |
107 | 110 | ||
108 | const baseUrl = `file://${__dirname}`; | 111 | const baseUrl = `file://${thisDir}`; |
109 | function getResourceUrl(relativePath: string): string { | 112 | function getResourceUrl(relativePath: string): string { |
110 | return new URL(relativePath, baseUrl).toString(); | 113 | return new URL(relativePath, baseUrl).toString(); |
111 | } | 114 | } |
@@ -117,15 +120,15 @@ const serviceInject: WebSource = { | |||
117 | url: getResourceUrl(serviceInjectRelativePath), | 120 | url: getResourceUrl(serviceInjectRelativePath), |
118 | }; | 121 | }; |
119 | 122 | ||
120 | let mainWindow: BrowserWindow | null = null; | 123 | let mainWindow: BrowserWindow | undefined; |
121 | 124 | ||
122 | const store = createMainStore(); | 125 | const store = createMainStore(); |
123 | init(store) | 126 | init(store) |
124 | .then((disposeCompositionRoot) => { | 127 | .then((disposeCompositionRoot) => { |
125 | app.on('will-quit', disposeCompositionRoot); | 128 | app.on('will-quit', disposeCompositionRoot); |
126 | }) | 129 | }) |
127 | .catch((err) => { | 130 | .catch((error) => { |
128 | log.log('Failed to initialize application', err); | 131 | log.log('Failed to initialize application', error); |
129 | }); | 132 | }); |
130 | 133 | ||
131 | const rendererBaseUrl = getResourceUrl('../renderer/'); | 134 | const rendererBaseUrl = getResourceUrl('../renderer/'); |
@@ -136,7 +139,7 @@ function shouldCancelMainWindowRequest(url: string, method: string): boolean { | |||
136 | let normalizedUrl: string; | 139 | let normalizedUrl: string; |
137 | try { | 140 | try { |
138 | normalizedUrl = new URL(url).toString(); | 141 | normalizedUrl = new URL(url).toString(); |
139 | } catch (_err) { | 142 | } catch { |
140 | return true; | 143 | return true; |
141 | } | 144 | } |
142 | if (isDevelopment) { | 145 | if (isDevelopment) { |
@@ -233,7 +236,7 @@ async function createWindow(): Promise<unknown> { | |||
233 | 'from webContents', | 236 | 'from webContents', |
234 | event.sender.id, | 237 | event.sender.id, |
235 | ); | 238 | ); |
236 | return null; | 239 | throw new Error('Invalid IPC call'); |
237 | } | 240 | } |
238 | return getSnapshot(store.shared); | 241 | return getSnapshot(store.shared); |
239 | }); | 242 | }); |
@@ -262,22 +265,22 @@ async function createWindow(): Promise<unknown> { | |||
262 | .then((data) => { | 265 | .then((data) => { |
263 | serviceInject.code = data; | 266 | serviceInject.code = data; |
264 | }) | 267 | }) |
265 | .catch((err) => { | 268 | .catch((error) => { |
266 | log.error('Error while reloading', serviceInjectPath, err); | 269 | log.error('Error while reloading', serviceInjectPath, error); |
267 | }) | 270 | }) |
268 | .then(() => { | 271 | .then(() => { |
269 | browserView.webContents.reload(); | 272 | browserView.webContents.reload(); |
270 | }) | 273 | }) |
271 | .catch((err) => { | 274 | .catch((error) => { |
272 | log.error('Failed to reload browserView', err); | 275 | log.error('Failed to reload browserView', error); |
273 | }); | 276 | }); |
274 | break; | 277 | break; |
275 | default: | 278 | default: |
276 | log.error('Unexpected action from UI renderer:', actionToDispatch); | 279 | log.error('Unexpected action from UI renderer:', actionToDispatch); |
277 | break; | 280 | break; |
278 | } | 281 | } |
279 | } catch (err) { | 282 | } catch (error) { |
280 | log.error('Error while dispatching renderer action', rawAction, err); | 283 | log.error('Error while dispatching renderer action', rawAction, error); |
281 | } | 284 | } |
282 | }); | 285 | }); |
283 | 286 | ||
@@ -285,9 +288,18 @@ async function createWindow(): Promise<unknown> { | |||
285 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); | 288 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); |
286 | }); | 289 | }); |
287 | 290 | ||
288 | ipcMain.handle(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => | 291 | ipcMain.handle(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => { |
289 | event.sender.id === browserView.webContents.id ? serviceInject : null, | 292 | if (event.sender.id !== browserView.webContents.id) { |
290 | ); | 293 | log.warn( |
294 | 'Unexpected', | ||
295 | ServiceToMainIpcMessage.ApiExposedInMainWorld, | ||
296 | 'from webContents', | ||
297 | event.sender.id, | ||
298 | ); | ||
299 | throw new Error('Invalid IPC call'); | ||
300 | } | ||
301 | return serviceInject; | ||
302 | }); | ||
291 | 303 | ||
292 | browserView.webContents.on('ipc-message', (_event, channel, ...args) => { | 304 | browserView.webContents.on('ipc-message', (_event, channel, ...args) => { |
293 | try { | 305 | try { |
@@ -303,8 +315,8 @@ async function createWindow(): Promise<unknown> { | |||
303 | log.error('Unknown IPC message:', channel, args); | 315 | log.error('Unknown IPC message:', channel, args); |
304 | break; | 316 | break; |
305 | } | 317 | } |
306 | } catch (err) { | 318 | } catch (error) { |
307 | log.error('Error while processing IPC message:', channel, args, err); | 319 | log.error('Error while processing IPC message:', channel, args, error); |
308 | } | 320 | } |
309 | }); | 321 | }); |
310 | 322 | ||
@@ -316,9 +328,7 @@ async function createWindow(): Promise<unknown> { | |||
316 | 328 | ||
317 | browserView.webContents.session.webRequest.onBeforeSendHeaders( | 329 | browserView.webContents.session.webRequest.onBeforeSendHeaders( |
318 | ({ url, requestHeaders }, callback) => { | 330 | ({ url, requestHeaders }, callback) => { |
319 | const requestUserAgent = url.match( | 331 | const requestUserAgent = /^[^:]+:\/\/accounts\.google\.[^./]+\//.test(url) |
320 | /^[^:]+:\/\/accounts\.google\.[^./]+\//, | ||
321 | ) | ||
322 | ? chromelessUserAgent | 332 | ? chromelessUserAgent |
323 | : userAgent; | 333 | : userAgent; |
324 | callback({ | 334 | callback({ |
@@ -332,15 +342,15 @@ async function createWindow(): Promise<unknown> { | |||
332 | 342 | ||
333 | browserView.webContents | 343 | browserView.webContents |
334 | .loadURL('https://gitlab.com/say-hi-to-sophie/sophie') | 344 | .loadURL('https://gitlab.com/say-hi-to-sophie/sophie') |
335 | .catch((err) => { | 345 | .catch((error) => { |
336 | log.error('Failed to load browser', err); | 346 | log.error('Failed to load browser', error); |
337 | }); | 347 | }); |
338 | 348 | ||
339 | return mainWindow.loadURL(pageUrl); | 349 | return mainWindow.loadURL(pageUrl); |
340 | } | 350 | } |
341 | 351 | ||
342 | app.on('second-instance', () => { | 352 | app.on('second-instance', () => { |
343 | if (mainWindow !== null) { | 353 | if (mainWindow !== undefined) { |
344 | if (!mainWindow.isVisible()) { | 354 | if (!mainWindow.isVisible()) { |
345 | mainWindow.show(); | 355 | mainWindow.show(); |
346 | } | 356 | } |
@@ -363,14 +373,14 @@ app | |||
363 | if (isDevelopment) { | 373 | if (isDevelopment) { |
364 | try { | 374 | try { |
365 | await installDevToolsExtensions(); | 375 | await installDevToolsExtensions(); |
366 | } catch (err) { | 376 | } catch (error) { |
367 | log.error('Failed to install devtools extensions', err); | 377 | log.error('Failed to install devtools extensions', error); |
368 | } | 378 | } |
369 | } | 379 | } |
370 | 380 | ||
371 | return createWindow(); | 381 | return createWindow(); |
372 | }) | 382 | }) |
373 | .catch((err) => { | 383 | .catch((error) => { |
374 | log.error('Failed to create window', err); | 384 | log.error('Failed to create window', error); |
375 | process.exit(1); | 385 | process.exit(1); |
376 | }); | 386 | }); |
diff --git a/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts b/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts index e92f706..a11a9da 100644 --- a/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts +++ b/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts | |||
@@ -17,9 +17,9 @@ | |||
17 | * | 17 | * |
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | import { watch } from 'fs'; | 20 | import { watch } from 'node:fs'; |
21 | import { readFile, stat, writeFile } from 'fs/promises'; | 21 | import { readFile, stat, writeFile } from 'node:fs/promises'; |
22 | import { join } from 'path'; | 22 | import path from 'node:path'; |
23 | 23 | ||
24 | import JSON5 from 'json5'; | 24 | import JSON5 from 'json5'; |
25 | import throttle from 'lodash-es/throttle'; | 25 | import throttle from 'lodash-es/throttle'; |
@@ -39,26 +39,26 @@ export default class ConfigPersistenceServiceImpl | |||
39 | 39 | ||
40 | private writingConfig = false; | 40 | private writingConfig = false; |
41 | 41 | ||
42 | private timeLastWritten: Date | null = null; | 42 | private timeLastWritten: Date | undefined; |
43 | 43 | ||
44 | constructor( | 44 | constructor( |
45 | private readonly userDataDir: string, | 45 | private readonly userDataDir: string, |
46 | private readonly configFileName: string = 'config.json5', | 46 | private readonly configFileName: string = 'config.json5', |
47 | ) { | 47 | ) { |
48 | this.configFileName = configFileName; | 48 | this.configFileName = configFileName; |
49 | this.configFilePath = join(this.userDataDir, this.configFileName); | 49 | this.configFilePath = path.join(this.userDataDir, this.configFileName); |
50 | } | 50 | } |
51 | 51 | ||
52 | async readConfig(): Promise<ReadConfigResult> { | 52 | async readConfig(): Promise<ReadConfigResult> { |
53 | let configStr; | 53 | let configStr; |
54 | try { | 54 | try { |
55 | configStr = await readFile(this.configFilePath, 'utf8'); | 55 | configStr = await readFile(this.configFilePath, 'utf8'); |
56 | } catch (err) { | 56 | } catch (error) { |
57 | if ((err as NodeJS.ErrnoException).code === 'ENOENT') { | 57 | if ((error as NodeJS.ErrnoException).code === 'ENOENT') { |
58 | log.debug('Config file', this.configFilePath, 'was not found'); | 58 | log.debug('Config file', this.configFilePath, 'was not found'); |
59 | return { found: false }; | 59 | return { found: false }; |
60 | } | 60 | } |
61 | throw err; | 61 | throw error; |
62 | } | 62 | } |
63 | log.info('Read config file', this.configFilePath); | 63 | log.info('Read config file', this.configFilePath); |
64 | return { | 64 | return { |
@@ -92,8 +92,8 @@ export default class ConfigPersistenceServiceImpl | |||
92 | const stats = await stat(this.configFilePath); | 92 | const stats = await stat(this.configFilePath); |
93 | mtime = stats.mtime; | 93 | mtime = stats.mtime; |
94 | log.trace('Config file last modified at', mtime); | 94 | log.trace('Config file last modified at', mtime); |
95 | } catch (err) { | 95 | } catch (error) { |
96 | if ((err as NodeJS.ErrnoException).code === 'ENOENT') { | 96 | if ((error as NodeJS.ErrnoException).code === 'ENOENT') { |
97 | log.debug( | 97 | log.debug( |
98 | 'Config file', | 98 | 'Config file', |
99 | this.configFilePath, | 99 | this.configFilePath, |
@@ -101,11 +101,11 @@ export default class ConfigPersistenceServiceImpl | |||
101 | ); | 101 | ); |
102 | return; | 102 | return; |
103 | } | 103 | } |
104 | throw err; | 104 | throw error; |
105 | } | 105 | } |
106 | if ( | 106 | if ( |
107 | !this.writingConfig && | 107 | !this.writingConfig && |
108 | (this.timeLastWritten === null || mtime > this.timeLastWritten) | 108 | (this.timeLastWritten === undefined || mtime > this.timeLastWritten) |
109 | ) { | 109 | ) { |
110 | log.debug( | 110 | log.debug( |
111 | 'Found a config file modified at', | 111 | 'Found a config file modified at', |
diff --git a/packages/main/src/stores/Config.ts b/packages/main/src/stores/Config.ts index 06dbdeb..ca90c0c 100644 --- a/packages/main/src/stores/Config.ts +++ b/packages/main/src/stores/Config.ts | |||
@@ -18,12 +18,7 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { | 21 | import { config as originalConfig, ThemeSource } from '@sophie/shared'; |
22 | config as originalConfig, | ||
23 | ConfigSnapshotIn, | ||
24 | ConfigSnapshotOut, | ||
25 | ThemeSource, | ||
26 | } from '@sophie/shared'; | ||
27 | import { Instance } from 'mobx-state-tree'; | 22 | import { Instance } from 'mobx-state-tree'; |
28 | 23 | ||
29 | export const config = originalConfig.actions((self) => ({ | 24 | export const config = originalConfig.actions((self) => ({ |
@@ -34,4 +29,4 @@ export const config = originalConfig.actions((self) => ({ | |||
34 | 29 | ||
35 | export interface Config extends Instance<typeof config> {} | 30 | export interface Config extends Instance<typeof config> {} |
36 | 31 | ||
37 | export type { ConfigSnapshotIn, ConfigSnapshotOut }; | 32 | export type { ConfigSnapshotIn, ConfigSnapshotOut } from '@sophie/shared'; |
diff --git a/packages/main/src/utils/log.ts b/packages/main/src/utils/log.ts index 5218721..0a632d8 100644 --- a/packages/main/src/utils/log.ts +++ b/packages/main/src/utils/log.ts | |||
@@ -18,8 +18,9 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | // eslint-disable-next-line unicorn/import-style -- Import the type `ChalkInstance` separately. | ||
21 | import chalk, { ChalkInstance } from 'chalk'; | 22 | import chalk, { ChalkInstance } from 'chalk'; |
22 | import loglevel, { Logger } from 'loglevel'; | 23 | import loglevel from 'loglevel'; |
23 | import prefix from 'loglevel-plugin-prefix'; | 24 | import prefix from 'loglevel-plugin-prefix'; |
24 | 25 | ||
25 | if (import.meta.env?.DEV) { | 26 | if (import.meta.env?.DEV) { |
@@ -54,7 +55,7 @@ prefix.apply(loglevel, { | |||
54 | }, | 55 | }, |
55 | }); | 56 | }); |
56 | 57 | ||
57 | export function getLogger(loggerName: string): Logger { | 58 | export function getLogger(loggerName: string): loglevel.Logger { |
58 | return loglevel.getLogger(loggerName); | 59 | return loglevel.getLogger(loggerName); |
59 | } | 60 | } |
60 | 61 | ||