From fb7118ff1c8f0dcd61f15e51b193512283d83fa1 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sun, 9 Jan 2022 22:16:29 +0100 Subject: build: Add eslint-plugin-unicorn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kristóf Marussy --- .electron-builder.config.cjs | 2 - .eslintrc.cjs | 22 ++ config/buildConstants.js | 10 +- config/fileURLToDirname.js | 10 - config/fileUrlToDirname.js | 10 + config/jest.config.base.js | 14 +- package.json | 3 +- packages/main/.eslintrc.cjs | 4 + packages/main/esbuild.config.js | 8 +- packages/main/jest.config.js | 5 +- .../src/controllers/__tests__/initConfig.spec.ts | 2 +- packages/main/src/controllers/initConfig.ts | 14 +- packages/main/src/devTools.ts | 3 +- packages/main/src/index.ts | 72 +++--- .../services/impl/ConfigPersistenceServiceImpl.ts | 24 +- packages/main/src/stores/Config.ts | 9 +- packages/main/src/utils/log.ts | 5 +- packages/preload/esbuild.config.js | 4 +- .../__tests__/createSophieRenderer.spec.ts | 12 +- .../src/contextBridge/createSophieRenderer.ts | 18 +- .../src/components/BrowserViewPlaceholder.tsx | 6 +- packages/renderer/src/components/StoreProvider.tsx | 5 +- packages/renderer/src/index.tsx | 4 +- packages/renderer/src/stores/RendererStore.ts | 4 +- packages/renderer/vite.config.js | 10 +- packages/service-inject/esbuild.config.js | 4 +- packages/service-preload/esbuild.config.js | 4 +- packages/service-preload/src/index.ts | 4 +- packages/service-shared/esbuild.config.js | 4 +- packages/shared/esbuild.config.js | 4 +- scripts/build.js | 12 +- scripts/update-electron-vendors.js | 65 ------ scripts/updateElectronVendors.js | 65 ++++++ scripts/watch.js | 52 ++--- yarn.lock | 248 ++++++++++++++++++++- 35 files changed, 509 insertions(+), 233 deletions(-) delete mode 100644 config/fileURLToDirname.js create mode 100644 config/fileUrlToDirname.js delete mode 100644 scripts/update-electron-vendors.js create mode 100644 scripts/updateElectronVendors.js diff --git a/.electron-builder.config.cjs b/.electron-builder.config.cjs index f406cc8..aa7d9e0 100644 --- a/.electron-builder.config.cjs +++ b/.electron-builder.config.cjs @@ -1,5 +1,3 @@ -// @ts-check - const { Arch } = require('electron-builder'); const { flipFuses, FuseV1Options, FuseVersion } = require('@electron/fuses'); const { join } = require('path'); diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 5bb3c21..e984179 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -12,6 +12,7 @@ module.exports = { 'plugin:jest/recommended', 'plugin:jest/style', 'plugin:prettier/recommended', + 'plugin:unicorn/recommended', ], env: { es6: true, @@ -51,6 +52,20 @@ module.exports = { 'newlines-between': 'always', }, ], + // Allows files with names same as the name of their default export. + 'unicorn/filename-case': [ + 'error', + { + cases: { + camelCase: true, + pascalCase: true, + }, + }, + ], + // Airbnb prefers forEach. + 'unicorn/no-array-for-each': 'off', + // Common abbreviations are known and readable. + 'unicorn/prevent-abbreviations': 'off', }, overrides: [ { @@ -120,5 +135,12 @@ module.exports = { 'import/no-relative-packages': 'off', }, }, + { + files: ['scripts/**/*.js'], + rules: { + // Scripts are allowed to `exit` abruptly. + 'unicorn/no-process-exit': 'off', + }, + }, ], }; diff --git a/config/buildConstants.js b/config/buildConstants.js index 3c55500..dfe2ab0 100644 --- a/config/buildConstants.js +++ b/config/buildConstants.js @@ -1,14 +1,14 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; -import fileURLToDirname from './fileURLToDirname.js'; +import fileUrlToDirname from './fileUrlToDirname.js'; -const thisDir = fileURLToDirname(import.meta.url); +const thisDir = fileUrlToDirname(import.meta.url); // We import this from a vite config, where top-level await is not available (es2021), // so we have to use the synchronous filesystem API. const electronVendorsJson = readFileSync( - join(thisDir, '../.electron-vendors.cache.json'), + path.join(thisDir, '../.electron-vendors.cache.json'), 'utf8', ); diff --git a/config/fileURLToDirname.js b/config/fileURLToDirname.js deleted file mode 100644 index 70654cb..0000000 --- a/config/fileURLToDirname.js +++ /dev/null @@ -1,10 +0,0 @@ -import { dirname } from 'path'; -import { fileURLToPath } from 'url'; - -/** - * @param {string} url - * @returns {string} - */ -export default function fileURLToDirname(url) { - return dirname(fileURLToPath(url)); -} diff --git a/config/fileUrlToDirname.js b/config/fileUrlToDirname.js new file mode 100644 index 0000000..9b51305 --- /dev/null +++ b/config/fileUrlToDirname.js @@ -0,0 +1,10 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +/** + * @param {string} url + * @returns {string} + */ +export default function fileUrlToDirname(url) { + return path.dirname(fileURLToPath(url)); +} diff --git a/config/jest.config.base.js b/config/jest.config.base.js index 21f93be..d9865f9 100644 --- a/config/jest.config.base.js +++ b/config/jest.config.base.js @@ -1,24 +1,24 @@ -import { join } from 'path'; +import path from 'node:path'; -import fileURLToDirname from './fileURLToDirname.js'; +import fileUrlToDirname from './fileUrlToDirname.js'; -const thisDir = fileURLToDirname(import.meta.url); +const thisDir = fileUrlToDirname(import.meta.url); /** @type {import('@jest/types').Config.InitialOptions} */ export default { transform: { - '\\.tsx?$': join(thisDir, 'jestEsbuildTransformer.js'), + '\\.tsx?$': path.join(thisDir, 'jestEsbuildTransformer.js'), }, extensionsToTreatAsEsm: ['.ts', '.tsx'], moduleNameMapper: { - '^@sophie/(.+)$': join(thisDir, '../packages/$1/src/index.ts'), + '^@sophie/(.+)$': path.join(thisDir, '../packages/$1/src/index.ts'), '^(\\.{1,2}/.*)\\.jsx?$': '$1', // Workaround for jest to recognize the vendored dependencies of chalk. - '^#ansi-styles$': join( + '^#ansi-styles$': path.join( thisDir, '../node_modules/chalk/source/vendor/ansi-styles/index.js', ), - '^#supports-color$': join( + '^#supports-color$': path.join( thisDir, '../node_modules/chalk/source/vendor/supports-color/index.js', ), diff --git a/package.json b/package.json index 5515d3d..9944155 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "g:typecheck": "cd $INIT_CWD && tsc", "types": "yarn workspaces foreach -vpt run types", "g:types": "cd $INIT_CWD && tsc -b tsconfig.build.json", - "update-electron-vendors": "node scripts/update-electron-vendors.js", + "update-electron-vendors": "node scripts/updateElectronVendors.js", "main": "yarn workspace @sophie/main", "preload": "yarn workspace @sophie/preload", "renderer": "yarn workspace @sophie/renderer", @@ -73,6 +73,7 @@ "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-unicorn": "^40.0.0", "git-repo-info": "^2.1.1", "jest": "^27.4.7", "prettier": "^2.5.1", diff --git a/packages/main/.eslintrc.cjs b/packages/main/.eslintrc.cjs index 548ea34..cab227c 100644 --- a/packages/main/.eslintrc.cjs +++ b/packages/main/.eslintrc.cjs @@ -3,4 +3,8 @@ module.exports = { node: true, browser: false, }, + rules: { + // This is an application, so we're allowed to `exit` from it. + 'unicorn/no-process-exit': 'off', + }, }; diff --git a/packages/main/esbuild.config.js b/packages/main/esbuild.config.js index d5f6f1e..ef0aa71 100644 --- a/packages/main/esbuild.config.js +++ b/packages/main/esbuild.config.js @@ -1,7 +1,7 @@ import getRepoInfo from 'git-repo-info'; import { node } from '../../config/buildConstants.js'; -import fileURLToDirname from '../../config/fileURLToDirname.js'; +import fileUrlToDirname from '../../config/fileUrlToDirname.js'; import getEsbuildConfig from '../../config/getEsbuildConfig.js'; const externalPackages = ['electron']; @@ -14,7 +14,7 @@ const gitInfo = getRepoInfo(); export default getEsbuildConfig( { - absWorkingDir: fileURLToDirname(import.meta.url), + absWorkingDir: fileUrlToDirname(import.meta.url), entryPoints: ['src/index.ts'], outfile: 'dist/index.cjs', format: 'cjs', @@ -23,9 +23,9 @@ export default getEsbuildConfig( external: externalPackages, }, { - VITE_DEV_SERVER_URL: process.env.VITE_DEV_SERVER_URL || null, + VITE_DEV_SERVER_URL: process.env.VITE_DEV_SERVER_URL || undefined, GIT_SHA: gitInfo.abbreviatedSha, GIT_BRANCH: gitInfo.branch, - BUILD_DATE: new Date().getTime(), + BUILD_DATE: Date.now(), }, ); diff --git a/packages/main/jest.config.js b/packages/main/jest.config.js index b86463c..9aaf344 100644 --- a/packages/main/jest.config.js +++ b/packages/main/jest.config.js @@ -1,3 +1,4 @@ -import rootConfig from '../../config/jest.config.base.js'; +import baseConfig from '../../config/jest.config.base.js'; -export default rootConfig; +// eslint-disable-next-line unicorn/prefer-export-from -- Can't export from default. +export default baseConfig; 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', () => { }); it('should throttle saving changes to the config file', () => { - mocked(persistenceService.writeConfig).mockResolvedValue(undefined); + mocked(persistenceService.writeConfig).mockResolvedValue(); config.setThemeSource('dark'); jest.advanceTimersByTime(lessThanThrottleMs); 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( ): Promise { log.trace('Initializing config controller'); - let lastSnapshotOnDisk: ConfigSnapshotOut | null = null; + let lastSnapshotOnDisk: ConfigSnapshotOut | undefined; async function readConfig(): Promise { const result = await persistenceService.readConfig(); @@ -46,8 +46,8 @@ export default async function initConfig( try { applySnapshot(config, result.data); lastSnapshotOnDisk = getSnapshot(config); - } catch (err) { - log.error('Failed to apply config snapshot', result.data, err); + } catch (error) { + log.error('Failed to apply config snapshot', result.data, error); } } return result.found; @@ -70,8 +70,8 @@ export default async function initConfig( debounce((snapshot) => { // We can compare snapshots by reference, since it is only recreated on store changes. if (lastSnapshotOnDisk !== snapshot) { - writeConfig().catch((err) => { - log.error('Failed to write config on config change', err); + writeConfig().catch((error) => { + log.error('Failed to write config on config change', error); }); } }, debounceTime), @@ -80,8 +80,8 @@ export default async function initConfig( const disposeWatcher = persistenceService.watchConfig(async () => { try { await readConfig(); - } catch (err) { - log.error('Failed to read config', err); + } catch (error) { + log.error('Failed to read config', error); } }, debounceTime); 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 { /* eslint-disable-next-line import/no-extraneous-dependencies, global-require, - @typescript-eslint/no-var-requires + @typescript-eslint/no-var-requires, + unicorn/prefer-module */ } = require('electron-devtools-installer') as typeof import('electron-devtools-installer'); 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 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { arch } from 'os'; -import { join } from 'path'; -import { URL } from 'url'; +import { arch } from 'node:os'; +import path from 'node:path'; +import { URL } from 'node:url'; import { ServiceToMainIpcMessage, @@ -101,11 +101,14 @@ app.setAboutPanelOptions({ version: '', }); +// eslint-disable-next-line unicorn/prefer-module -- Electron apps run in a commonjs environment. +const thisDir = __dirname; + function getResourcePath(relativePath: string): string { - return join(__dirname, relativePath); + return path.join(thisDir, relativePath); } -const baseUrl = `file://${__dirname}`; +const baseUrl = `file://${thisDir}`; function getResourceUrl(relativePath: string): string { return new URL(relativePath, baseUrl).toString(); } @@ -117,15 +120,15 @@ const serviceInject: WebSource = { url: getResourceUrl(serviceInjectRelativePath), }; -let mainWindow: BrowserWindow | null = null; +let mainWindow: BrowserWindow | undefined; const store = createMainStore(); init(store) .then((disposeCompositionRoot) => { app.on('will-quit', disposeCompositionRoot); }) - .catch((err) => { - log.log('Failed to initialize application', err); + .catch((error) => { + log.log('Failed to initialize application', error); }); const rendererBaseUrl = getResourceUrl('../renderer/'); @@ -136,7 +139,7 @@ function shouldCancelMainWindowRequest(url: string, method: string): boolean { let normalizedUrl: string; try { normalizedUrl = new URL(url).toString(); - } catch (_err) { + } catch { return true; } if (isDevelopment) { @@ -233,7 +236,7 @@ async function createWindow(): Promise { 'from webContents', event.sender.id, ); - return null; + throw new Error('Invalid IPC call'); } return getSnapshot(store.shared); }); @@ -262,22 +265,22 @@ async function createWindow(): Promise { .then((data) => { serviceInject.code = data; }) - .catch((err) => { - log.error('Error while reloading', serviceInjectPath, err); + .catch((error) => { + log.error('Error while reloading', serviceInjectPath, error); }) .then(() => { browserView.webContents.reload(); }) - .catch((err) => { - log.error('Failed to reload browserView', err); + .catch((error) => { + log.error('Failed to reload browserView', error); }); break; default: log.error('Unexpected action from UI renderer:', actionToDispatch); break; } - } catch (err) { - log.error('Error while dispatching renderer action', rawAction, err); + } catch (error) { + log.error('Error while dispatching renderer action', rawAction, error); } }); @@ -285,9 +288,18 @@ async function createWindow(): Promise { webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); }); - ipcMain.handle(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => - event.sender.id === browserView.webContents.id ? serviceInject : null, - ); + ipcMain.handle(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => { + if (event.sender.id !== browserView.webContents.id) { + log.warn( + 'Unexpected', + ServiceToMainIpcMessage.ApiExposedInMainWorld, + 'from webContents', + event.sender.id, + ); + throw new Error('Invalid IPC call'); + } + return serviceInject; + }); browserView.webContents.on('ipc-message', (_event, channel, ...args) => { try { @@ -303,8 +315,8 @@ async function createWindow(): Promise { log.error('Unknown IPC message:', channel, args); break; } - } catch (err) { - log.error('Error while processing IPC message:', channel, args, err); + } catch (error) { + log.error('Error while processing IPC message:', channel, args, error); } }); @@ -316,9 +328,7 @@ async function createWindow(): Promise { browserView.webContents.session.webRequest.onBeforeSendHeaders( ({ url, requestHeaders }, callback) => { - const requestUserAgent = url.match( - /^[^:]+:\/\/accounts\.google\.[^./]+\//, - ) + const requestUserAgent = /^[^:]+:\/\/accounts\.google\.[^./]+\//.test(url) ? chromelessUserAgent : userAgent; callback({ @@ -332,15 +342,15 @@ async function createWindow(): Promise { browserView.webContents .loadURL('https://gitlab.com/say-hi-to-sophie/sophie') - .catch((err) => { - log.error('Failed to load browser', err); + .catch((error) => { + log.error('Failed to load browser', error); }); return mainWindow.loadURL(pageUrl); } app.on('second-instance', () => { - if (mainWindow !== null) { + if (mainWindow !== undefined) { if (!mainWindow.isVisible()) { mainWindow.show(); } @@ -363,14 +373,14 @@ app if (isDevelopment) { try { await installDevToolsExtensions(); - } catch (err) { - log.error('Failed to install devtools extensions', err); + } catch (error) { + log.error('Failed to install devtools extensions', error); } } return createWindow(); }) - .catch((err) => { - log.error('Failed to create window', err); + .catch((error) => { + log.error('Failed to create window', error); process.exit(1); }); 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 @@ * * SPDX-License-Identifier: AGPL-3.0-only */ -import { watch } from 'fs'; -import { readFile, stat, writeFile } from 'fs/promises'; -import { join } from 'path'; +import { watch } from 'node:fs'; +import { readFile, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; import JSON5 from 'json5'; import throttle from 'lodash-es/throttle'; @@ -39,26 +39,26 @@ export default class ConfigPersistenceServiceImpl private writingConfig = false; - private timeLastWritten: Date | null = null; + private timeLastWritten: Date | undefined; constructor( private readonly userDataDir: string, private readonly configFileName: string = 'config.json5', ) { this.configFileName = configFileName; - this.configFilePath = join(this.userDataDir, this.configFileName); + this.configFilePath = path.join(this.userDataDir, this.configFileName); } async readConfig(): Promise { let configStr; try { configStr = await readFile(this.configFilePath, 'utf8'); - } catch (err) { - if ((err as NodeJS.ErrnoException).code === 'ENOENT') { + } catch (error) { + if ((error as NodeJS.ErrnoException).code === 'ENOENT') { log.debug('Config file', this.configFilePath, 'was not found'); return { found: false }; } - throw err; + throw error; } log.info('Read config file', this.configFilePath); return { @@ -92,8 +92,8 @@ export default class ConfigPersistenceServiceImpl const stats = await stat(this.configFilePath); mtime = stats.mtime; log.trace('Config file last modified at', mtime); - } catch (err) { - if ((err as NodeJS.ErrnoException).code === 'ENOENT') { + } catch (error) { + if ((error as NodeJS.ErrnoException).code === 'ENOENT') { log.debug( 'Config file', this.configFilePath, @@ -101,11 +101,11 @@ export default class ConfigPersistenceServiceImpl ); return; } - throw err; + throw error; } if ( !this.writingConfig && - (this.timeLastWritten === null || mtime > this.timeLastWritten) + (this.timeLastWritten === undefined || mtime > this.timeLastWritten) ) { log.debug( '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 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { - config as originalConfig, - ConfigSnapshotIn, - ConfigSnapshotOut, - ThemeSource, -} from '@sophie/shared'; +import { config as originalConfig, ThemeSource } from '@sophie/shared'; import { Instance } from 'mobx-state-tree'; export const config = originalConfig.actions((self) => ({ @@ -34,4 +29,4 @@ export const config = originalConfig.actions((self) => ({ export interface Config extends Instance {} -export type { ConfigSnapshotIn, ConfigSnapshotOut }; +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 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +// eslint-disable-next-line unicorn/import-style -- Import the type `ChalkInstance` separately. import chalk, { ChalkInstance } from 'chalk'; -import loglevel, { Logger } from 'loglevel'; +import loglevel from 'loglevel'; import prefix from 'loglevel-plugin-prefix'; if (import.meta.env?.DEV) { @@ -54,7 +55,7 @@ prefix.apply(loglevel, { }, }); -export function getLogger(loggerName: string): Logger { +export function getLogger(loggerName: string): loglevel.Logger { return loglevel.getLogger(loggerName); } diff --git a/packages/preload/esbuild.config.js b/packages/preload/esbuild.config.js index d888987..87e91d8 100644 --- a/packages/preload/esbuild.config.js +++ b/packages/preload/esbuild.config.js @@ -1,9 +1,9 @@ import { chrome } from '../../config/buildConstants.js'; -import fileURLToDirname from '../../config/fileURLToDirname.js'; +import fileUrlToDirname from '../../config/fileUrlToDirname.js'; import getEsbuildConfig from '../../config/getEsbuildConfig.js'; export default getEsbuildConfig({ - absWorkingDir: fileURLToDirname(import.meta.url), + absWorkingDir: fileUrlToDirname(import.meta.url), entryPoints: ['src/index.ts'], outfile: 'dist/index.cjs', format: 'cjs', diff --git a/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts index b0af280..88b0077 100644 --- a/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts +++ b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts @@ -45,7 +45,7 @@ const { default: createSophieRenderer } = await import( ); const event: Electron.IpcRendererEvent = - null as unknown as Electron.IpcRendererEvent; + undefined as unknown as Electron.IpcRendererEvent; const snapshot: SharedStoreSnapshotIn = { shouldUseDarkColors: true, @@ -183,7 +183,7 @@ describe('SharedStoreConnector', () => { it('should catch listener errors', () => { mocked(listener.onPatch).mockImplementation(() => { - throw new Error(); + throw new Error('listener error'); }); expect(() => onSharedStorePatch(event, patch)).not.toThrow(); }); @@ -193,7 +193,7 @@ describe('SharedStoreConnector', () => { describe('after the listener threw in onPatch', () => { beforeEach(() => { mocked(listener.onPatch).mockImplementation(() => { - throw new Error(); + throw new Error('listener error'); }); onSharedStorePatch(event, patch); listener.onPatch.mockRestore(); @@ -205,7 +205,9 @@ describe('SharedStoreConnector', () => { describe('when a listener failed to register due to IPC error', () => { beforeEach(async () => { - mocked(ipcRenderer.invoke).mockRejectedValue(new Error()); + mocked(ipcRenderer.invoke).mockRejectedValue( + new Error('ipcRenderer error'), + ); try { await sut.onSharedStoreChange(listener); } catch { @@ -237,7 +239,7 @@ describe('SharedStoreConnector', () => { beforeEach(async () => { mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot); mocked(listener.onSnapshot).mockImplementation(() => { - throw new Error(); + throw new Error('listener error'); }); try { await sut.onSharedStoreChange(listener); diff --git a/packages/preload/src/contextBridge/createSophieRenderer.ts b/packages/preload/src/contextBridge/createSophieRenderer.ts index b97503d..3174fed 100644 --- a/packages/preload/src/contextBridge/createSophieRenderer.ts +++ b/packages/preload/src/contextBridge/createSophieRenderer.ts @@ -34,7 +34,7 @@ import type { IJsonPatch } from 'mobx-state-tree'; class SharedStoreConnector { private onSharedStoreChangeCalled = false; - private listener: SharedStoreListener | null = null; + private listener: SharedStoreListener | undefined; constructor(private readonly allowReplaceListener: boolean) { ipcRenderer.on( @@ -43,9 +43,9 @@ class SharedStoreConnector { try { // `mobx-state-tree` will validate the patch, so we can safely cast here. this.listener?.onPatch(patch as IJsonPatch); - } catch (err) { - log.error('Shared store listener onPatch failed', err); - this.listener = null; + } catch (error) { + log.error('Shared store listener onPatch failed', error); + this.listener = undefined; } }, ); @@ -57,14 +57,14 @@ class SharedStoreConnector { } this.onSharedStoreChangeCalled = true; let success = false; - let snapshot: unknown | null = null; + let snapshot: unknown; try { snapshot = await ipcRenderer.invoke( RendererToMainIpcMessage.GetSharedStoreSnapshot, ); success = true; - } catch (err) { - log.error('Failed to get initial shared store snapshot', err); + } catch (error) { + log.error('Failed to get initial shared store snapshot', error); } if (success) { if (sharedStore.is(snapshot)) { @@ -84,10 +84,10 @@ function dispatchAction(actionToDispatch: Action): void { const parsedAction = action.parse(actionToDispatch); try { ipcRenderer.send(RendererToMainIpcMessage.DispatchAction, parsedAction); - } catch (err) { + } catch (error) { // Do not leak IPC failure details into the main world. const message = 'Failed to dispatch action'; - log.error(message, actionToDispatch, err); + log.error(message, actionToDispatch, error); throw new Error(message); } } diff --git a/packages/renderer/src/components/BrowserViewPlaceholder.tsx b/packages/renderer/src/components/BrowserViewPlaceholder.tsx index 8f055e7..58407ee 100644 --- a/packages/renderer/src/components/BrowserViewPlaceholder.tsx +++ b/packages/renderer/src/components/BrowserViewPlaceholder.tsx @@ -44,15 +44,15 @@ export default observer(() => { [store], ); - const resizeObserverRef = useRef(null); + const resizeObserverRef = useRef(); const ref = useCallback( (element: HTMLElement | null) => { - if (resizeObserverRef.current !== null) { + if (resizeObserverRef.current !== undefined) { resizeObserverRef.current.disconnect(); } if (element === null) { - resizeObserverRef.current = null; + resizeObserverRef.current = undefined; return; } resizeObserverRef.current = new ResizeObserver(onResize); diff --git a/packages/renderer/src/components/StoreProvider.tsx b/packages/renderer/src/components/StoreProvider.tsx index bb8495c..3360a43 100644 --- a/packages/renderer/src/components/StoreProvider.tsx +++ b/packages/renderer/src/components/StoreProvider.tsx @@ -22,11 +22,12 @@ import React, { createContext, useContext } from 'react'; import type { RendererStore } from '../stores/RendererStore'; -const StoreContext = createContext(null); +// eslint-disable-next-line unicorn/no-useless-undefined -- `createContext` expects 1 parameter. +const StoreContext = createContext(undefined); export function useStore(): RendererStore { const store = useContext(StoreContext); - if (store === null) { + if (store === undefined) { throw new Error('useStore can only be called inside of StoreProvider'); } return store; diff --git a/packages/renderer/src/index.tsx b/packages/renderer/src/index.tsx index d900e50..a42a30c 100644 --- a/packages/renderer/src/index.tsx +++ b/packages/renderer/src/index.tsx @@ -45,8 +45,8 @@ if (isDevelopment) { const store = createAndConnectRendererStore(window.sophieRenderer); if (isDevelopment) { - exposeToReduxDevtools(store).catch((err) => { - log.error('Cannot initialize redux devtools', err); + exposeToReduxDevtools(store).catch((error) => { + log.error('Cannot initialize redux devtools', error); }); } diff --git a/packages/renderer/src/stores/RendererStore.ts b/packages/renderer/src/stores/RendererStore.ts index 0b78ce1..4cc5163 100644 --- a/packages/renderer/src/stores/RendererStore.ts +++ b/packages/renderer/src/stores/RendererStore.ts @@ -86,8 +86,8 @@ export function createAndConnectRendererStore( applyPatch(store.shared, patch); }, }) - .catch((err) => { - log.error('Failed to connect to shared store', err); + .catch((error) => { + log.error('Failed to connect to shared store', error); }); return store; diff --git a/packages/renderer/vite.config.js b/packages/renderer/vite.config.js index e20e0f1..cb0203c 100644 --- a/packages/renderer/vite.config.js +++ b/packages/renderer/vite.config.js @@ -1,15 +1,15 @@ /* eslint-disable no-process-env */ /* eslint-env node */ -import { builtinModules } from 'module'; -import { join } from 'path'; +import { builtinModules } from 'node:module'; +import path from 'node:path'; import react from '@vitejs/plugin-react'; import { banner, chrome } from '../../config/buildConstants.js'; -import fileURLToDirname from '../../config/fileURLToDirname.js'; +import fileUrlToDirname from '../../config/fileUrlToDirname.js'; -const thisDir = fileURLToDirname(import.meta.url); +const thisDir = fileUrlToDirname(import.meta.url); const mode = process.env.MODE || 'development'; @@ -24,7 +24,7 @@ export default { logLevel: 'info', mode, root: thisDir, - cacheDir: join(thisDir, '../../.vite'), + cacheDir: path.join(thisDir, '../../.vite'), plugins: [ react({ babel: { diff --git a/packages/service-inject/esbuild.config.js b/packages/service-inject/esbuild.config.js index 795b0f6..d8698ac 100644 --- a/packages/service-inject/esbuild.config.js +++ b/packages/service-inject/esbuild.config.js @@ -1,9 +1,9 @@ import { chrome } from '../../config/buildConstants.js'; -import fileURLToDirname from '../../config/fileURLToDirname.js'; +import fileUrlToDirname from '../../config/fileUrlToDirname.js'; import getEsbuildConfig from '../../config/getEsbuildConfig.js'; export default getEsbuildConfig({ - absWorkingDir: fileURLToDirname(import.meta.url), + absWorkingDir: fileUrlToDirname(import.meta.url), entryPoints: ['src/index.ts'], outfile: 'dist/index.js', format: 'iife', diff --git a/packages/service-preload/esbuild.config.js b/packages/service-preload/esbuild.config.js index d888987..87e91d8 100644 --- a/packages/service-preload/esbuild.config.js +++ b/packages/service-preload/esbuild.config.js @@ -1,9 +1,9 @@ import { chrome } from '../../config/buildConstants.js'; -import fileURLToDirname from '../../config/fileURLToDirname.js'; +import fileUrlToDirname from '../../config/fileUrlToDirname.js'; import getEsbuildConfig from '../../config/getEsbuildConfig.js'; export default getEsbuildConfig({ - absWorkingDir: fileURLToDirname(import.meta.url), + absWorkingDir: fileUrlToDirname(import.meta.url), entryPoints: ['src/index.ts'], outfile: 'dist/index.cjs', format: 'cjs', diff --git a/packages/service-preload/src/index.ts b/packages/service-preload/src/index.ts index 2bbfefd..bb4a62d 100644 --- a/packages/service-preload/src/index.ts +++ b/packages/service-preload/src/index.ts @@ -61,6 +61,6 @@ async function fetchAndExecuteInjectScript(): Promise { await webFrame.executeJavaScriptInIsolatedWorld(0, [injectSource]); } -fetchAndExecuteInjectScript().catch((err) => { - log.error('Failed to fetch inject source:', err); +fetchAndExecuteInjectScript().catch((error) => { + log.error('Failed to fetch inject source:', error); }); diff --git a/packages/service-shared/esbuild.config.js b/packages/service-shared/esbuild.config.js index 2b0dec8..62e3d2a 100644 --- a/packages/service-shared/esbuild.config.js +++ b/packages/service-shared/esbuild.config.js @@ -1,9 +1,9 @@ import { chrome, node } from '../../config/buildConstants.js'; -import fileURLToDirname from '../../config/fileURLToDirname.js'; +import fileUrlToDirname from '../../config/fileUrlToDirname.js'; import getEsbuildConfig from '../../config/getEsbuildConfig.js'; export default getEsbuildConfig({ - absWorkingDir: fileURLToDirname(import.meta.url), + absWorkingDir: fileUrlToDirname(import.meta.url), entryPoints: ['src/index.ts'], outfile: 'dist/index.mjs', format: 'esm', diff --git a/packages/shared/esbuild.config.js b/packages/shared/esbuild.config.js index 44501bd..7a79ce6 100644 --- a/packages/shared/esbuild.config.js +++ b/packages/shared/esbuild.config.js @@ -1,9 +1,9 @@ import { chrome, node } from '../../config/buildConstants.js'; -import fileURLToDirname from '../../config/fileURLToDirname.js'; +import fileUrlToDirname from '../../config/fileUrlToDirname.js'; import getEsbuildConfig from '../../config/getEsbuildConfig.js'; export default getEsbuildConfig({ - absWorkingDir: fileURLToDirname(import.meta.url), + absWorkingDir: fileUrlToDirname(import.meta.url), entryPoints: ['src/index.ts'], outfile: 'dist/index.mjs', format: 'esm', diff --git a/scripts/build.js b/scripts/build.js index 88267e5..66a1506 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,11 +1,11 @@ -import { join } from 'path'; +import path from 'node:path'; import { build as esbuildBuild } from 'esbuild'; import { build as viteBuild } from 'vite'; -import fileURLToDirname from '../config/fileURLToDirname.js'; +import fileUrlToDirname from '../config/fileUrlToDirname.js'; -const thisDir = fileURLToDirname(import.meta.url); +const thisDir = fileUrlToDirname(import.meta.url); /** * @param {string} packageName @@ -26,7 +26,7 @@ async function buildPackageEsbuild(packageName) { */ function buildPackageVite(packageName) { return viteBuild({ - configFile: join(thisDir, `../packages/${packageName}/vite.config.js`), + configFile: path.join(thisDir, `../packages/${packageName}/vite.config.js`), }); } @@ -52,7 +52,7 @@ function buildAll() { ]); } -buildAll().catch((err) => { - console.error(err); +buildAll().catch((error) => { + console.error(error); process.exit(1); }); diff --git a/scripts/update-electron-vendors.js b/scripts/update-electron-vendors.js deleted file mode 100644 index 6ff5c06..0000000 --- a/scripts/update-electron-vendors.js +++ /dev/null @@ -1,65 +0,0 @@ -import { execSync } from 'child_process'; -import { writeFile } from 'fs/promises'; -import { join } from 'path'; - -import electronPath from 'electron'; - -import fileURLToDirname from '../config/fileURLToDirname.js'; - -const thisDir = fileURLToDirname(import.meta.url); - -/** - * Returns versions of electron vendors - * The performance of this feature is very poor and can be improved - * @see https://github.com/electron/electron/issues/28006 - * - * @returns {NodeJS.ProcessVersions} - */ -function getVendors() { - const output = execSync( - `${electronPath.toString()} -p "JSON.stringify(process.versions)"`, - { - env: { ELECTRON_RUN_AS_NODE: '1' }, - encoding: 'utf-8', - }, - ); - - // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- Read untyped output. - return JSON.parse(output); -} - -/** - * Generates the `.browserlistrc` and `.electron-vendors.cache.json` files. - * - * @returns Promise - */ -function updateVendors() { - const electronRelease = getVendors(); - - const nodeMajorVersion = electronRelease.node.split('.')[0]; - const chromeMajorVersion = - electronRelease.v8.split('.')[0] + electronRelease.v8.split('.')[1]; - - const browserslistrcPath = join(thisDir, '../.browserslistrc'); - - return Promise.all([ - writeFile( - join(thisDir, '../.electron-vendors.cache.json'), - `${JSON.stringify( - { - chrome: chromeMajorVersion, - node: nodeMajorVersion, - }, - null, - 2, - )}\n`, - ), - - writeFile(browserslistrcPath, `Chrome ${chromeMajorVersion}\n`, 'utf8'), - ]); -} - -updateVendors().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/scripts/updateElectronVendors.js b/scripts/updateElectronVendors.js new file mode 100644 index 0000000..5e8ab36 --- /dev/null +++ b/scripts/updateElectronVendors.js @@ -0,0 +1,65 @@ +import { execSync } from 'node:child_process'; +import { writeFile } from 'node:fs/promises'; +import path from 'node:path'; + +import electronPath from 'electron'; + +import fileUrlToDirname from '../config/fileUrlToDirname.js'; + +const thisDir = fileUrlToDirname(import.meta.url); + +/** + * Returns versions of electron vendors + * The performance of this feature is very poor and can be improved + * @see https://github.com/electron/electron/issues/28006 + * + * @returns {NodeJS.ProcessVersions} + */ +function getVendors() { + const output = execSync( + `${electronPath.toString()} -p "JSON.stringify(process.versions)"`, + { + env: { ELECTRON_RUN_AS_NODE: '1' }, + encoding: 'utf-8', + }, + ); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- Read untyped output. + return JSON.parse(output); +} + +/** + * Generates the `.browserlistrc` and `.electron-vendors.cache.json` files. + * + * @returns Promise + */ +function updateVendors() { + const electronRelease = getVendors(); + + const nodeMajorVersion = electronRelease.node.split('.')[0]; + const chromeMajorVersion = + electronRelease.v8.split('.')[0] + electronRelease.v8.split('.')[1]; + + const browserslistrcPath = path.join(thisDir, '../.browserslistrc'); + + return Promise.all([ + writeFile( + path.join(thisDir, '../.electron-vendors.cache.json'), + `${JSON.stringify( + { + chrome: chromeMajorVersion, + node: nodeMajorVersion, + }, + undefined, + 2, + )}\n`, + ), + + writeFile(browserslistrcPath, `Chrome ${chromeMajorVersion}\n`, 'utf8'), + ]); +} + +updateVendors().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/scripts/watch.js b/scripts/watch.js index cf5dbfd..455cfd9 100644 --- a/scripts/watch.js +++ b/scripts/watch.js @@ -1,21 +1,21 @@ -import { spawn } from 'child_process'; -import { join } from 'path'; +import { spawn } from 'node:child_process'; +import path from 'node:path'; import { watch } from 'chokidar'; import electronPath from 'electron'; import { build as esbuildBuild } from 'esbuild'; import { createServer } from 'vite'; -import fileURLToDirname from '../config/fileURLToDirname.js'; +import fileUrlToDirname from '../config/fileUrlToDirname.js'; /** @type {string} */ -const thisDir = fileURLToDirname(import.meta.url); +const thisDir = fileUrlToDirname(import.meta.url); /** @type {string} */ -const sharedModule = join(thisDir, '../packages/shared/dist/index.mjs'); +const sharedModule = path.join(thisDir, '../packages/shared/dist/index.mjs'); /** @type {string} */ -const serviceSharedModule = join( +const serviceSharedModule = path.join( thisDir, '../packages/service-shared/dist/index.mjs', ); @@ -48,7 +48,7 @@ async function setupEsbuildWatcher(packageName, extraPaths, callback) { const incrementalBuild = await esbuildBuild(config); const paths = [ - join(thisDir, `../packages/${packageName}/src`), + path.join(thisDir, `../packages/${packageName}/src`), ...(extraPaths || []), ]; const watcher = watch(paths, { @@ -64,18 +64,18 @@ async function setupEsbuildWatcher(packageName, extraPaths, callback) { .rebuild?.() .then(() => { if (callback) { - console.log(`\u26a1 Reloading package ${packageName}`); + console.log(`\u26A1 Reloading package ${packageName}`); callback(); } }) - .catch((err) => { - if (typeof err === 'object' && 'errors' in err) { + .catch((error) => { + if (typeof error === 'object' && 'errors' in error) { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- We just checked. - const { errors } = err; + const { errors } = error; if (Array.isArray(errors)) { const errCount = errors.length; console.error( - '\ud83d\udd25', + '\uD83D\uDD25', errCount, errCount > 1 ? 'errors' : 'error', 'while rebuilding package', @@ -85,10 +85,10 @@ async function setupEsbuildWatcher(packageName, extraPaths, callback) { } } console.error( - '\ud83d\udd25', + '\uD83D\uDD25', 'error while rebuilding package', packageName, - err, + error, ); }); }); @@ -106,7 +106,7 @@ async function setupDevServer(packageName) { clearScreen: false, }, }, - configFile: join(thisDir, `../packages/${packageName}/vite.config.js`), + configFile: path.join(thisDir, `../packages/${packageName}/vite.config.js`), }); await viteDevServer.listen(); return viteDevServer; @@ -155,16 +155,16 @@ function setupMainPackageWatcher(viteDevServer) { process.env.VITE_DEV_SERVER_URL = `${protocol}//${hostOrDefault}:${portOrDefault}/`; /** @type {import('child_process').ChildProcessByStdio - | null} */ - let spawnProcess = null; + | undefined} */ + let spawnProcess; return setupEsbuildWatcher( 'main', [serviceSharedModule, sharedModule], () => { - if (spawnProcess !== null) { + if (spawnProcess !== undefined) { spawnProcess.kill('SIGINT'); - spawnProcess = null; + spawnProcess = undefined; } spawnProcess = spawn(String(electronPath), ['.'], { @@ -188,11 +188,11 @@ async function setupDevEnvironment() { process.env.MODE = 'development'; process.env.NODE_ENV = 'development'; - /** @type {import('vite').ViteDevServer | null} */ - let viteDevServer = null; + /** @type {import('vite').ViteDevServer | undefined} */ + let viteDevServer; /** @type {(event: import('vite').HMRPayload) => void} */ const sendEvent = (event) => { - if (viteDevServer !== null) { + if (viteDevServer !== undefined) { viteDevServer.ws.send(event); } }; @@ -216,16 +216,16 @@ async function setupDevEnvironment() { ), ]); - if (viteDevServer === null) { + if (viteDevServer === undefined) { console.error('Failed to create vite dev server'); return; } - console.log('\ud83c\udf80 Sophie is starting up'); + console.log('\uD83C\uDF80 Sophie is starting up'); await setupMainPackageWatcher(viteDevServer); } -setupDevEnvironment().catch((err) => { - console.error(err); +setupDevEnvironment().catch((error) => { + console.error(error); process.exit(1); }); diff --git a/yarn.lock b/yarn.lock index 3b96a84..4a391c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -173,7 +173,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.16.7": +"@babel/helper-validator-identifier@npm:^7.15.7, @babel/helper-validator-identifier@npm:^7.16.7": version: 7.16.7 resolution: "@babel/helper-validator-identifier@npm:7.16.7" checksum: dbb3db9d184343152520a209b5684f5e0ed416109cde82b428ca9c759c29b10c7450657785a8b5c5256aa74acc6da491c1f0cf6b784939f7931ef82982051b69 @@ -1552,6 +1552,13 @@ __metadata: languageName: node linkType: hard +"@types/normalize-package-data@npm:^2.4.0": + version: 2.4.1 + resolution: "@types/normalize-package-data@npm:2.4.1" + checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 + languageName: node + linkType: hard + "@types/parse-json@npm:^4.0.0": version: 4.0.0 resolution: "@types/parse-json@npm:4.0.0" @@ -2493,6 +2500,13 @@ __metadata: languageName: node linkType: hard +"builtin-modules@npm:^3.0.0": + version: 3.2.0 + resolution: "builtin-modules@npm:3.2.0" + checksum: 0265aa1ba78e1a16f4e18668d815cb43fb364e6a6b8aa9189c6f44c7b894a551a43b323c40206959d2d4b2568c1f2805607ad6c88adc306a776ce6904cca6715 + languageName: node + linkType: hard + "cacache@npm:^15.2.0": version: 15.3.0 resolution: "cacache@npm:15.3.0" @@ -2647,7 +2661,7 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.2.0": +"ci-info@npm:^3.2.0, ci-info@npm:^3.3.0": version: 3.3.0 resolution: "ci-info@npm:3.3.0" checksum: c3d86fe374938ecda5093b1ba39acb535d8309185ba3f23587747c6a057e63f45419b406d880304dbc0e1d72392c9a33e42fe9a1e299209bc0ded5efaa232b66 @@ -2661,6 +2675,15 @@ __metadata: languageName: node linkType: hard +"clean-regexp@npm:^1.0.0": + version: 1.0.0 + resolution: "clean-regexp@npm:1.0.0" + dependencies: + escape-string-regexp: ^1.0.5 + checksum: 0b1ce281b07da2463c6882ea2e8409119b6cabbd9f687cdbdcee942c45b2b9049a2084f7b5f228c63ef9f21e722963ae0bfe56a735dbdbdd92512867625a7e40 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -4167,6 +4190,30 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-unicorn@npm:^40.0.0": + version: 40.0.0 + resolution: "eslint-plugin-unicorn@npm:40.0.0" + dependencies: + "@babel/helper-validator-identifier": ^7.15.7 + ci-info: ^3.3.0 + clean-regexp: ^1.0.0 + eslint-utils: ^3.0.0 + esquery: ^1.4.0 + indent-string: ^4.0.0 + is-builtin-module: ^3.1.0 + lodash: ^4.17.21 + pluralize: ^8.0.0 + read-pkg-up: ^7.0.1 + regexp-tree: ^0.1.24 + safe-regex: ^2.1.1 + semver: ^7.3.5 + strip-indent: ^3.0.0 + peerDependencies: + eslint: ">=7.32.0" + checksum: 2397ab10b28bd67e08c227c894e7066619e5b6140d4fd6df228782e0e3e2c2518f5ca839bd8e20ebfd7adde341beab71763f8ca38b3c2c1fc59bd0b5e0e5a3c9 + languageName: node + linkType: hard + "eslint-scope@npm:^5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" @@ -4936,6 +4983,13 @@ __metadata: languageName: node linkType: hard +"hosted-git-info@npm:^2.1.4": + version: 2.8.9 + resolution: "hosted-git-info@npm:2.8.9" + checksum: c955394bdab888a1e9bb10eb33029e0f7ce5a2ac7b3f158099dc8c486c99e73809dca609f5694b223920ca2174db33d32b12f9a2a47141dc59607c29da5a62dd + languageName: node + linkType: hard + "hosted-git-info@npm:^4.0.2": version: 4.0.2 resolution: "hosted-git-info@npm:4.0.2" @@ -5222,6 +5276,15 @@ __metadata: languageName: node linkType: hard +"is-builtin-module@npm:^3.1.0": + version: 3.1.0 + resolution: "is-builtin-module@npm:3.1.0" + dependencies: + builtin-modules: ^3.0.0 + checksum: f1e5dd2cd5f252d4d799b20a0c8c4f7e9c399c4d141749af76ca0121058d4062c3015d026f1b1409dd3d2a4ddfb9b15cf6eb9c370fed53fea8652ce35b5e95cb + languageName: node + linkType: hard + "is-callable@npm:^1.1.4, is-callable@npm:^1.2.4": version: 1.2.4 resolution: "is-callable@npm:1.2.4" @@ -6384,7 +6447,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.10, lodash@npm:^4.17.15, lodash@npm:^4.7.0": +"lodash@npm:^4.17.10, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.7.0": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -6569,6 +6632,13 @@ __metadata: languageName: node linkType: hard +"min-indent@npm:^1.0.0": + version: 1.0.1 + resolution: "min-indent@npm:1.0.1" + checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 + languageName: node + linkType: hard + "minimatch@npm:3.0.4, minimatch@npm:^3.0.4": version: 3.0.4 resolution: "minimatch@npm:3.0.4" @@ -6813,6 +6883,18 @@ __metadata: languageName: node linkType: hard +"normalize-package-data@npm:^2.5.0": + version: 2.5.0 + resolution: "normalize-package-data@npm:2.5.0" + dependencies: + hosted-git-info: ^2.1.4 + resolve: ^1.10.0 + semver: 2 || 3 || 4 || 5 + validate-npm-package-license: ^3.0.1 + checksum: 7999112efc35a6259bc22db460540cae06564aa65d0271e3bdfa86876d08b0e578b7b5b0028ee61b23f1cae9fc0e7847e4edc0948d3068a39a2a82853efc8499 + languageName: node + linkType: hard + "normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" @@ -7152,7 +7234,7 @@ __metadata: languageName: node linkType: hard -"path-parse@npm:^1.0.6": +"path-parse@npm:^1.0.6, path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a @@ -7220,6 +7302,13 @@ __metadata: languageName: node linkType: hard +"pluralize@npm:^8.0.0": + version: 8.0.0 + resolution: "pluralize@npm:8.0.0" + checksum: 08931d4a6a4a5561a7f94f67a31c17e6632cb21e459ab3ff4f6f629d9a822984cf8afef2311d2005fbea5d7ef26016ebb090db008e2d8bce39d0a9a9d218736e + languageName: node + linkType: hard + "postcss@npm:^8.4.5": version: 8.4.5 resolution: "postcss@npm:8.4.5" @@ -7499,6 +7588,29 @@ __metadata: languageName: node linkType: hard +"read-pkg-up@npm:^7.0.1": + version: 7.0.1 + resolution: "read-pkg-up@npm:7.0.1" + dependencies: + find-up: ^4.1.0 + read-pkg: ^5.2.0 + type-fest: ^0.8.1 + checksum: e4e93ce70e5905b490ca8f883eb9e48b5d3cebc6cd4527c25a0d8f3ae2903bd4121c5ab9c5a3e217ada0141098eeb661313c86fa008524b089b8ed0b7f165e44 + languageName: node + linkType: hard + +"read-pkg@npm:^5.2.0": + version: 5.2.0 + resolution: "read-pkg@npm:5.2.0" + dependencies: + "@types/normalize-package-data": ^2.4.0 + normalize-package-data: ^2.5.0 + parse-json: ^5.0.0 + type-fest: ^0.6.0 + checksum: eb696e60528b29aebe10e499ba93f44991908c57d70f2d26f369e46b8b9afc208ef11b4ba64f67630f31df8b6872129e0a8933c8c53b7b4daf0eace536901222 + languageName: node + linkType: hard + "readable-stream@npm:^2.2.2, readable-stream@npm:~2.3.6": version: 2.3.7 resolution: "readable-stream@npm:2.3.7" @@ -7541,6 +7653,15 @@ __metadata: languageName: node linkType: hard +"regexp-tree@npm:^0.1.24, regexp-tree@npm:~0.1.1": + version: 0.1.24 + resolution: "regexp-tree@npm:0.1.24" + bin: + regexp-tree: bin/regexp-tree + checksum: 5807013289d9205288d665e0f8d8cff94843dfd55fdedd1833eb9d9bbd07188a37dfa02942ec5cdc671180037f715148fac1ba6f18fd6be4268e5a8feb49d340 + languageName: node + linkType: hard + "regexp.prototype.flags@npm:^1.3.1": version: 1.3.1 resolution: "regexp.prototype.flags@npm:1.3.1" @@ -7625,6 +7746,19 @@ __metadata: languageName: node linkType: hard +"resolve@npm:^1.10.0": + version: 1.21.0 + resolution: "resolve@npm:1.21.0" + dependencies: + is-core-module: ^2.8.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: d7d9092a5c04a048bea16c7e5a2eb605ac3e8363a0cc5644de1fde17d5028e8d5f4343aab1d99bd327b98e91a66ea83e242718150c64dfedcb96e5e7aad6c4f5 + languageName: node + linkType: hard + "resolve@npm:^1.12.0, resolve@npm:^1.20.0": version: 1.20.0 resolution: "resolve@npm:1.20.0" @@ -7645,6 +7779,19 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@^1.10.0#~builtin": + version: 1.21.0 + resolution: "resolve@patch:resolve@npm%3A1.21.0#~builtin::version=1.21.0&hash=07638b" + dependencies: + is-core-module: ^2.8.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: a0a4d1f7409e73190f31f901f8a619960bb3bd4ae38ba3a54c7ea7e1c87758d28a73256bb8d6a35996a903d1bf14f53883f0dcac6c571c063cb8162d813ad26e + languageName: node + linkType: hard + "resolve@patch:resolve@^1.12.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin": version: 1.20.0 resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin::version=1.20.0&hash=07638b" @@ -7757,6 +7904,15 @@ __metadata: languageName: node linkType: hard +"safe-regex@npm:^2.1.1": + version: 2.1.1 + resolution: "safe-regex@npm:2.1.1" + dependencies: + regexp-tree: ~0.1.1 + checksum: 5d734e2193c63ef0cb00f60c0244e0f8a30ecb31923633cd34636808d6a7c4c206d650017953ae1db8bc33967c2f06af33488dea6f038f4e38212beb7bed77b4 + languageName: node + linkType: hard + "safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" @@ -7838,6 +7994,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:2 || 3 || 4 || 5": + version: 5.7.1 + resolution: "semver@npm:5.7.1" + bin: + semver: ./bin/semver + checksum: 57fd0acfd0bac382ee87cd52cd0aaa5af086a7dc8d60379dfe65fea491fb2489b6016400813930ecd61fd0952dae75c115287a1b16c234b1550887117744dfaf + languageName: node + linkType: hard + "semver@npm:^6.0.0, semver@npm:^6.2.0, semver@npm:^6.3.0": version: 6.3.0 resolution: "semver@npm:6.3.0" @@ -8014,6 +8179,7 @@ __metadata: eslint-plugin-prettier: ^4.0.0 eslint-plugin-react: ^7.28.0 eslint-plugin-react-hooks: ^4.3.0 + eslint-plugin-unicorn: ^40.0.0 git-repo-info: ^2.1.1 jest: ^27.4.7 preload: ^0.1.0 @@ -8062,6 +8228,40 @@ __metadata: languageName: node linkType: hard +"spdx-correct@npm:^3.0.0": + version: 3.1.1 + resolution: "spdx-correct@npm:3.1.1" + dependencies: + spdx-expression-parse: ^3.0.0 + spdx-license-ids: ^3.0.0 + checksum: 77ce438344a34f9930feffa61be0eddcda5b55fc592906ef75621d4b52c07400a97084d8701557b13f7d2aae0cb64f808431f469e566ef3fe0a3a131dcb775a6 + languageName: node + linkType: hard + +"spdx-exceptions@npm:^2.1.0": + version: 2.3.0 + resolution: "spdx-exceptions@npm:2.3.0" + checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 + languageName: node + linkType: hard + +"spdx-expression-parse@npm:^3.0.0": + version: 3.0.1 + resolution: "spdx-expression-parse@npm:3.0.1" + dependencies: + spdx-exceptions: ^2.1.0 + spdx-license-ids: ^3.0.0 + checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde + languageName: node + linkType: hard + +"spdx-license-ids@npm:^3.0.0": + version: 3.0.11 + resolution: "spdx-license-ids@npm:3.0.11" + checksum: 1da1acb090257773e60b022094050e810ae9fec874dc1461f65dc0400cd42dd830ab2df6e64fb49c2db3dce386dd0362110780e1b154db7c0bb413488836aaeb + languageName: node + linkType: hard + "sprintf-js@npm:^1.1.2": version: 1.1.2 resolution: "sprintf-js@npm:1.1.2" @@ -8206,6 +8406,15 @@ __metadata: languageName: node linkType: hard +"strip-indent@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-indent@npm:3.0.0" + dependencies: + min-indent: ^1.0.0 + checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -8273,6 +8482,13 @@ __metadata: languageName: node linkType: hard +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae + languageName: node + linkType: hard + "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" @@ -8536,6 +8752,20 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^0.6.0": + version: 0.6.0 + resolution: "type-fest@npm:0.6.0" + checksum: b2188e6e4b21557f6e92960ec496d28a51d68658018cba8b597bd3ef757721d1db309f120ae987abeeda874511d14b776157ff809f23c6d1ce8f83b9b2b7d60f + languageName: node + linkType: hard + +"type-fest@npm:^0.8.1": + version: 0.8.1 + resolution: "type-fest@npm:0.8.1" + checksum: d61c4b2eba24009033ae4500d7d818a94fd6d1b481a8111612ee141400d5f1db46f199c014766b9fa9b31a6a7374d96fc748c6d688a78a3ce5a33123839becb7 + languageName: node + linkType: hard + "typedarray-to-buffer@npm:^3.1.5": version: 3.1.5 resolution: "typedarray-to-buffer@npm:3.1.5" @@ -8717,6 +8947,16 @@ __metadata: languageName: node linkType: hard +"validate-npm-package-license@npm:^3.0.1": + version: 3.0.4 + resolution: "validate-npm-package-license@npm:3.0.4" + dependencies: + spdx-correct: ^3.0.0 + spdx-expression-parse: ^3.0.0 + checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad + languageName: node + linkType: hard + "verror@npm:^1.10.0": version: 1.10.1 resolution: "verror@npm:1.10.1" -- cgit v1.2.3-54-g00ecf