From 97d51a7763b14c92ee71ff9a012311dd9498d803 Mon Sep 17 00:00:00 2001 From: Vijay Raghavan Aravamudhan Date: Sun, 8 Aug 2021 00:01:37 +0000 Subject: refactor: path-references refactoring and using 'import' instead of 'require' (#1752) * refactor references to 'userData' and 'appData' directories to move hardcoding into single location * convert to es6 for lower memory usage as per https://codesource.io/the-difference-between-import-and-require-in-javascript/ --- src/api/server/ServerApi.js | 50 +++++++++------------- src/components/services/content/ServiceWebview.js | 4 +- src/components/services/tabs/TabBarSortableList.js | 9 ---- src/containers/settings/RecipesScreen.js | 12 +++--- src/electron/Settings.js | 6 +-- src/electron/ipc-api/appIndicator.js | 4 +- src/electron/ipc-api/download.js | 4 +- src/electron/ipc-api/localServer.js | 5 ++- src/electron/macOSPermissions.js | 46 +++++++++++--------- src/electron/webview-ime-focus.js | 4 +- src/environment.js | 25 +++++++---- src/helpers/recipe-helpers.js | 11 +++-- src/helpers/service-helpers.js | 16 +++---- src/helpers/userAgent-helpers.js | 5 +-- src/index.js | 14 +++--- src/internal-server/start.js | 4 +- src/lib/Tray.js | 4 +- src/models/Recipe.js | 6 +-- src/models/Service.js | 4 +- src/scripts/add-crowdin-contributors.js | 2 +- src/scripts/build-theme-info.js | 4 +- src/scripts/link-readme.js | 2 +- src/stores/AppStore.js | 6 +-- src/stores/RecipesStore.js | 9 ++-- src/stores/ServicesStore.js | 21 +++++---- src/webview/darkmode.js | 10 ++--- src/webview/lib/RecipeWebview.js | 8 ++-- src/webview/recipe.js | 20 ++++----- 28 files changed, 149 insertions(+), 166 deletions(-) (limited to 'src') diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index f91aeb23a..2111eb80b 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js @@ -1,6 +1,6 @@ -import path from 'path'; +import { join } from 'path'; import tar from 'tar'; -import fs from 'fs-extra'; +import { readdirSync, statSync, writeFileSync, copySync, ensureDirSync, pathExistsSync, readJsonSync, removeSync } from 'fs-extra'; import { app, require as remoteRequire } from '@electron/remote'; import ServiceModel from '../../models/Service'; @@ -13,7 +13,7 @@ import OrderModel from '../../models/Order'; import { sleep } from '../../helpers/async-helpers'; import { SERVER_NOT_LOADED } from '../../config'; -import { osArch, osPlatform, RECIPES_PATH } from '../../environment'; +import { osArch, osPlatform, asarRecipesPath, userDataRecipesPath, userDataPath } from '../../environment'; import apiBase from '../apiBase'; import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; @@ -311,11 +311,10 @@ export default class ServerApi { // Recipes async getInstalledRecipes() { const recipesDirectory = getRecipeDirectory(); - const paths = fs - .readdirSync(recipesDirectory) + const paths = readdirSync(recipesDirectory) .filter( file => - fs.statSync(path.join(recipesDirectory, file)).isDirectory() && + statSync(join(recipesDirectory, file)).isDirectory() && file !== 'temp' && file !== 'dev', ); @@ -381,17 +380,17 @@ export default class ServerApi { async getRecipePackage(recipeId) { try { - const recipesDirectory = path.join(app.getPath('userData'), 'recipes'); - const recipeTempDirectory = path.join(recipesDirectory, 'temp', recipeId); - const tempArchivePath = path.join(recipeTempDirectory, 'recipe.tar.gz'); + const recipesDirectory = userDataRecipesPath(); + const recipeTempDirectory = join(recipesDirectory, 'temp', recipeId); + const tempArchivePath = join(recipeTempDirectory, 'recipe.tar.gz'); - const internalRecipeFile = path.join(RECIPES_PATH, `${recipeId}.tar.gz`); + const internalRecipeFile = asarRecipesPath(`${recipeId}.tar.gz`); - fs.ensureDirSync(recipeTempDirectory); + ensureDirSync(recipeTempDirectory); let archivePath; - if (fs.existsSync(internalRecipeFile)) { + if (pathExistsSync(internalRecipeFile)) { debug('[ServerApi::getRecipePackage] Using internal recipe file'); archivePath = internalRecipeFile; } else { @@ -403,7 +402,7 @@ export default class ServerApi { const res = await fetch(packageUrl); debug('Recipe downloaded', recipeId); const buffer = await res.buffer(); - fs.writeFileSync(archivePath, buffer); + writeFileSync(archivePath, buffer); } debug(archivePath); @@ -420,13 +419,11 @@ export default class ServerApi { await sleep(10); - const { id } = fs.readJsonSync( - path.join(recipeTempDirectory, 'package.json'), - ); - const recipeDirectory = path.join(recipesDirectory, id); - fs.copySync(recipeTempDirectory, recipeDirectory); - fs.remove(recipeTempDirectory); - fs.remove(path.join(recipesDirectory, recipeId, 'recipe.tar.gz')); + const { id } = readJsonSync(join(recipeTempDirectory, 'package.json')); + const recipeDirectory = join(recipesDirectory, id); + copySync(recipeTempDirectory, recipeDirectory); + removeSync(recipeTempDirectory); + removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz')); return id; } catch (err) { @@ -475,14 +472,10 @@ export default class ServerApi { } async getLegacyServices() { - const file = path.join( - app.getPath('userData'), - 'settings', - 'services.json', - ); + const file = userDataPath('settings', 'services.json'); try { - const config = fs.readJsonSync(file); + const config = readJsonSync(file); if (Object.prototype.hasOwnProperty.call(config, 'services')) { const services = await Promise.all( @@ -614,11 +607,10 @@ export default class ServerApi { _getDevRecipes() { const recipesDirectory = getDevRecipeDirectory(); try { - const paths = fs - .readdirSync(recipesDirectory) + const paths = readdirSync(recipesDirectory) .filter( file => - fs.statSync(path.join(recipesDirectory, file)).isDirectory() && + statSync(join(recipesDirectory, file)).isDirectory() && file !== 'temp', ); diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index 4edbde5e2..3b499a5db 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; import { observable, reaction } from 'mobx'; import ElectronWebView from 'react-electron-web-view'; -import path from 'path'; +import { join } from 'path'; import ServiceModel from '../../../models/Service'; @@ -59,7 +59,7 @@ class ServiceWebview extends Component { isSpellcheckerEnabled, } = this.props; - const preloadScript = path.join(__dirname, '../../../', 'webview', 'recipe.js'); + const preloadScript = join(__dirname, '..', '..', '..', 'webview', 'recipe.js'); return ( ))} - {/*
  • - -
  • */} ); } diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js index 93503fb0e..ff3c688fa 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.js @@ -1,11 +1,9 @@ import { shell } from 'electron'; -import { app } from '@electron/remote'; -import fs from 'fs-extra'; +import { ensureDirSync, readJsonSync } from 'fs-extra'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { autorun } from 'mobx'; import { inject, observer } from 'mobx-react'; -import path from 'path'; import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; import RecipeStore from '../../stores/RecipesStore'; @@ -15,7 +13,7 @@ import UserStore from '../../stores/UserStore'; import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; -import { RECIPES_PATH } from '../../environment'; +import { asarRecipesPath, userDataRecipesPath } from '../../environment'; import { communityRecipesStore } from '../../features/communityRecipes'; import RecipePreview from '../../models/RecipePreview'; import AppStore from '../../stores/AppStore'; @@ -45,7 +43,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend constructor(props) { super(props); - this.customRecipes = fs.readJsonSync(path.join(RECIPES_PATH, 'all.json')); + this.customRecipes = readJsonSync(asarRecipesPath('all.json')); } componentDidMount() { @@ -140,7 +138,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend || recipes.installRecipeRequest.isExecuting || recipePreviews.searchRecipePreviewsRequest.isExecuting; - const recipeDirectory = path.join(app.getPath('userData'), 'recipes', 'dev'); + const recipeDirectory = userDataRecipesPath('dev'); return ( @@ -157,7 +155,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend recipeFilter={filter} recipeDirectory={recipeDirectory} openRecipeDirectory={async () => { - await fs.ensureDir(recipeDirectory); + ensureDirSync(recipeDirectory); shell.openExternal(`file://${recipeDirectory}`); }} openDevDocs={() => { diff --git a/src/electron/Settings.js b/src/electron/Settings.js index 2f3f8261a..4dd9f8245 100644 --- a/src/electron/Settings.js +++ b/src/electron/Settings.js @@ -1,8 +1,6 @@ import { observable, toJS } from 'mobx'; import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra'; -import path from 'path'; - -import { SETTINGS_PATH } from '../environment'; +import { userDataPath } from '../environment'; const debug = require('debug')('Ferdi:Settings'); @@ -58,6 +56,6 @@ export default class Settings { } get settingsFile() { - return path.join(SETTINGS_PATH, `${this.type === 'app' ? 'settings' : this.type}.json`); + return userDataPath('config', `${this.type === 'app' ? 'settings' : this.type}.json`); } } diff --git a/src/electron/ipc-api/appIndicator.js b/src/electron/ipc-api/appIndicator.js index 0691e5170..c6c261d0f 100644 --- a/src/electron/ipc-api/appIndicator.js +++ b/src/electron/ipc-api/appIndicator.js @@ -1,5 +1,5 @@ import { app, ipcMain } from 'electron'; -import path from 'path'; +import { join } from 'path'; import { autorun } from 'mobx'; import { isMac, isWindows, isLinux } from '../../environment'; @@ -9,7 +9,7 @@ const FILE_EXTENSION = isWindows ? 'ico' : 'png'; let isTrayIconEnabled; function getAsset(type, asset) { - return path.join( + return join( __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`, ); } diff --git a/src/electron/ipc-api/download.js b/src/electron/ipc-api/download.js index 7f8718924..ba261ba1e 100644 --- a/src/electron/ipc-api/download.js +++ b/src/electron/ipc-api/download.js @@ -1,7 +1,7 @@ import { ipcMain, dialog, BrowserWindow } from 'electron'; import { download } from 'electron-dl'; import mime from 'mime-types'; -import fs from 'fs-extra'; +import { writeFileSync } from 'fs-extra'; const debug = require('debug')('Ferdi:ipcApi:download'); @@ -37,7 +37,7 @@ export default (params) => { if (saveDialog.canceled) return; const binaryImage = decodeBase64Image(content); - fs.writeFileSync(saveDialog.filePath, binaryImage, 'binary'); + writeFileSync(saveDialog.filePath, binaryImage, 'binary'); debug('File blob saved to', saveDialog.filePath); } catch (err) { diff --git a/src/electron/ipc-api/localServer.js b/src/electron/ipc-api/localServer.js index 493253e17..1ed4b7167 100644 --- a/src/electron/ipc-api/localServer.js +++ b/src/electron/ipc-api/localServer.js @@ -1,6 +1,7 @@ -import { ipcMain, app } from 'electron'; +import { ipcMain } from 'electron'; import net from 'net'; import { LOCAL_HOSTNAME } from '../../config'; +import { userDataPath } from '../../environment'; import startServer from '../../internal-server/start'; const DEFAULT_PORT = 45569; @@ -37,7 +38,7 @@ export default (params) => { } console.log('Starting local server on port', port); - startServer(app.getPath('userData'), port); + startServer(userDataPath(), port); params.mainWindow.webContents.send('localServerPort', { port, diff --git a/src/electron/macOSPermissions.js b/src/electron/macOSPermissions.js index c114f4843..887af2903 100644 --- a/src/electron/macOSPermissions.js +++ b/src/electron/macOSPermissions.js @@ -1,45 +1,43 @@ -import { app, systemPreferences, dialog } from 'electron'; -import fs from 'fs'; +import { systemPreferences, dialog } from 'electron'; +import { pathExistsSync, mkdirSync, writeFileSync } from 'fs-extra'; import macosVersion from 'macos-version'; -import path from 'path'; +import { dirname } from 'path'; import { askForScreenCaptureAccess } from 'node-mac-permissions'; +import { userDataPath } from '../environment'; const debug = require('debug')('Ferdi:macOSPermissions'); -const permissionExists = macosVersion.isGreaterThanOrEqualTo('10.15'); -const filePath = path.join( - app.getPath('userData'), - '.has-app-requested-screen-capture-permissions', -); +const isExplicitScreenCapturePermissionReqd = macosVersion.isGreaterThanOrEqualTo('10.15'); +debug(`Should check explicitly for screen-capture permissions: ${isExplicitScreenCapturePermissionReqd}`); -function hasPromptedForPermission() { - if (!permissionExists) { - return false; - } +const filePath = userDataPath('.has-app-requested-screen-capture-permissions'); - if (filePath && fs.existsSync(filePath)) { - return true; +function hasPromptedForScreenCapturePermission() { + if (!isExplicitScreenCapturePermissionReqd) { + return false; } - return false; + debug('Checking if status file exists'); + return filePath && pathExistsSync(filePath); } -function hasScreenCapturePermission() { - if (!permissionExists) { +function hasScreenCapturePermissionAlreadyBeenGranted() { + if (!isExplicitScreenCapturePermissionReqd) { return true; } const screenCaptureStatus = systemPreferences.getMediaAccessStatus('screen'); + debug(`screen-capture permissions status: ${screenCaptureStatus}`); return screenCaptureStatus === 'granted'; } function createStatusFile() { try { - fs.writeFileSync(filePath, ''); + writeFileSync(filePath, ''); } catch (error) { if (error.code === 'ENOENT') { - fs.mkdirSync(path.dirname(filePath)); - fs.writeFileSync(filePath, ''); + mkdirSync(dirname(filePath)); + writeFileSync(filePath, ''); } throw error; @@ -51,7 +49,13 @@ export const askFormacOSPermissions = async mainWindow => { systemPreferences.askForMediaAccess('camera'); systemPreferences.askForMediaAccess('microphone'); - if (!hasPromptedForPermission() && !hasScreenCapturePermission()) { + if (hasScreenCapturePermissionAlreadyBeenGranted()) { + debug('Already obtained screen-capture permissions - writing status file'); + createStatusFile(); + return; + } + + if (!hasPromptedForScreenCapturePermission()) { debug('Checking screen capture permissions'); const { response } = await dialog.showMessageBox(mainWindow, { diff --git a/src/electron/webview-ime-focus.js b/src/electron/webview-ime-focus.js index b9421eb06..e187ee0b4 100644 --- a/src/electron/webview-ime-focus.js +++ b/src/electron/webview-ime-focus.js @@ -1,5 +1,5 @@ -const { webContents } = require('@electron/remote'); -const { releaseDocumentFocus } = require('./webview-ime-focus-helpers'); +import { webContents } from '@electron/remote'; +import { releaseDocumentFocus } from './webview-ime-focus-helpers'; function giveWebviewDocumentFocus(element) { releaseDocumentFocus(); diff --git a/src/environment.js b/src/environment.js index 7b560acb6..7267f93a6 100644 --- a/src/environment.js +++ b/src/environment.js @@ -1,10 +1,11 @@ import os from 'os'; -import path from 'path'; +import { join } from 'path'; import { is, api as electronApi } from 'electron-util'; import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme'; +import osName from 'os-name'; import { LIVE_FERDI_API, DEV_FRANZ_API, @@ -25,8 +26,6 @@ import { import { asarPath } from './helpers/asar-helpers'; import * as buildInfo from './buildInfo.json'; // eslint-disable-line import/no-unresolved -const osName = require('os-name'); - export const { app } = electronApi; export const ferdiVersion = app.getVersion(); export const electronVersion = process.versions.electron; @@ -36,24 +35,32 @@ export const nodeVersion = process.versions.node; // Set app directory before loading user modules if (process.env.FERDI_APPDATA_DIR != null) { app.setPath('appData', process.env.FERDI_APPDATA_DIR); - app.setPath('userData', path.join(app.getPath('appData'))); + app.setPath('userData', join(app.getPath('appData'))); } else if (process.env.PORTABLE_EXECUTABLE_DIR != null) { app.setPath('appData', process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`); - app.setPath('userData', path.join(app.getPath('appData'), `${app.name}AppData`)); + app.setPath('userData', join(app.getPath('appData'), `${app.name}AppData`)); } else if (is.windows) { app.setPath('appData', process.env.APPDATA); - app.setPath('userData', path.join(app.getPath('appData'), app.name)); + app.setPath('userData', join(app.getPath('appData'), app.name)); } export const isDevMode = is.development; if (isDevMode) { - app.setPath('userData', path.join(app.getPath('appData'), `${app.name}Dev`)); + app.setPath('userData', join(app.getPath('appData'), `${app.name}Dev`)); } -export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); +export function userDataPath(...segments) { + return join(app.getPath('userData'), ...([segments].flat())); +} + +export function userDataRecipesPath(...segments) { + return userDataPath('recipes', ...([segments].flat())); +} // Replacing app.asar is not beautiful but unfortunately necessary -export const RECIPES_PATH = asarPath(path.join(__dirname, 'recipes')); +export function asarRecipesPath(...segments) { + return join(asarPath(join(__dirname, 'recipes')), ...([segments].flat())); +} export const useLiveAPI = process.env.USE_LIVE_API; const useLocalAPI = process.env.USE_LOCAL_API; diff --git a/src/helpers/recipe-helpers.js b/src/helpers/recipe-helpers.js index 7daa0aaab..7e4bfa85a 100644 --- a/src/helpers/recipe-helpers.js +++ b/src/helpers/recipe-helpers.js @@ -1,12 +1,12 @@ -import path from 'path'; -import { app } from '@electron/remote'; +import { parse } from 'path'; +import { userDataRecipesPath } from '../environment'; export function getRecipeDirectory(id = '') { - return path.join(app.getPath('userData'), 'recipes', id); + return userDataRecipesPath(id); } export function getDevRecipeDirectory(id = '') { - return path.join(app.getPath('userData'), 'recipes', 'dev', id); + return userDataRecipesPath('dev', id); } export function loadRecipeConfig(recipeId) { @@ -19,8 +19,7 @@ export function loadRecipeConfig(recipeId) { let config = require(configPath); const moduleConfigPath = require.resolve(configPath); - const paths = path.parse(moduleConfigPath); - config.path = paths.dir; + config.path = parse(moduleConfigPath).dir; return config; } catch (e) { diff --git a/src/helpers/service-helpers.js b/src/helpers/service-helpers.js index 28d483182..745f40dd9 100644 --- a/src/helpers/service-helpers.js +++ b/src/helpers/service-helpers.js @@ -1,18 +1,16 @@ -import path from 'path'; -import { app } from '@electron/remote'; -import fs from 'fs-extra'; +import { readdirSync, removeSync } from 'fs-extra'; +import { userDataPath } from '../environment'; -export function getServicePartitionsDirectory() { - return path.join(app.getPath('userData'), 'Partitions'); +export function getServicePartitionsDirectory(...segments) { + return userDataPath('Partitions', ...([segments].flat())); } export function removeServicePartitionDirectory(id = '', addServicePrefix = false) { - const servicePartition = path.join(getServicePartitionsDirectory(), `${addServicePrefix ? 'service-' : ''}${id}`); - - return fs.remove(servicePartition); + const servicePartition = getServicePartitionsDirectory(`${addServicePrefix ? 'service-' : ''}${id}`); + return removeSync(servicePartition); } export async function getServiceIdsFromPartitions() { - const files = await fs.readdir(getServicePartitionsDirectory()); + const files = readdirSync(getServicePartitionsDirectory()); return files.filter((n) => n !== '__chrome_extension'); } diff --git a/src/helpers/userAgent-helpers.js b/src/helpers/userAgent-helpers.js index 9c9c8f132..ede5e6dc4 100644 --- a/src/helpers/userAgent-helpers.js +++ b/src/helpers/userAgent-helpers.js @@ -1,11 +1,10 @@ import os from 'os'; import macosVersion from 'macos-version'; +import { chrome } from 'useragent-generator'; import { chromeVersion, isMac, isWindows, is64Bit, osArch, osRelease, } from '../environment'; -const uaGenerator = require('useragent-generator'); - function macOS() { const version = macosVersion(); let cpuName = os.cpus()[0].model.split(' ')[0]; @@ -38,5 +37,5 @@ export default function userAgent() { platformString = linux(); } - return uaGenerator.chrome({ os: platformString, version: chromeVersion }); + return chrome({ os: platformString, version: chromeVersion }); } diff --git a/src/index.js b/src/index.js index 78ab9bef2..3264fdc63 100644 --- a/src/index.js +++ b/src/index.js @@ -2,8 +2,8 @@ import { app, BrowserWindow, shell, ipcMain, session } from 'electron'; -import fs from 'fs-extra'; -import path from 'path'; +import { emptyDirSync, ensureFileSync } from 'fs-extra'; +import { join } from 'path'; import windowStateKeeper from 'electron-window-state'; import { enforceMacOSAppLocation } from 'electron-util'; import ms from 'ms'; @@ -19,6 +19,8 @@ import { isWindows, isLinux, aboutAppDetails, + userDataRecipesPath, + userDataPath, } from './environment'; import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; @@ -63,8 +65,8 @@ function onDidLoad(fn) { } // Ensure that the recipe directory exists -fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); -fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); +emptyDirSync(userDataRecipesPath('temp')); +ensureFileSync(userDataPath('window-state.json')); // Set App ID for Windows if (isWindows) { @@ -193,7 +195,7 @@ const createWindow = () => { nodeIntegration: true, contextIsolation: false, webviewTag: true, - preload: path.join(__dirname, 'sentry.js'), + preload: join(__dirname, 'sentry.js'), enableRemoteModule: true, }, }); @@ -401,7 +403,7 @@ app.on('ready', () => { program: process.execPath, arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, iconPath: asarPath( - path.join( + join( isDevMode ? `${__dirname}../src/` : __dirname, 'assets/images/taskbar/win32/display.ico', ), diff --git a/src/internal-server/start.js b/src/internal-server/start.js index cb8ef56c8..5ccc1330e 100644 --- a/src/internal-server/start.js +++ b/src/internal-server/start.js @@ -18,9 +18,9 @@ const fold = require('@adonisjs/fold'); const { Ignitor } = require('@adonisjs/ignitor'); const fs = require('fs-extra'); -const os = require('os'); const path = require('path'); const { LOCAL_HOSTNAME } = require('../config'); +const { isWindows } = require('../environment'); process.env.ENV_PATH = path.join(__dirname, 'env.ini'); @@ -35,7 +35,7 @@ module.exports = async (userPath, port) => { await fs.writeFile(dbPath, dbTemplate); // Change permissions to ensure to file is not read-only - if (os.platform() === 'win32') { + if (isWindows) { // eslint-disable-next-line no-bitwise fs.chmodSync(dbPath, fs.statSync(dbPath).mode | 146); } diff --git a/src/lib/Tray.js b/src/lib/Tray.js index f37b4eb7b..f5970f7e7 100644 --- a/src/lib/Tray.js +++ b/src/lib/Tray.js @@ -1,7 +1,7 @@ import { app, Menu, nativeImage, nativeTheme, systemPreferences, Tray, ipcMain, } from 'electron'; -import path from 'path'; +import { join } from 'path'; import macosVersion from 'macos-version'; import { isMac, isWindows, isLinux } from '../environment'; @@ -174,7 +174,7 @@ export default class TrayIcon { platform = `${platform}-dark`; } - return nativeImage.createFromPath(path.join( + return nativeImage.createFromPath(join( __dirname, '..', 'assets', 'images', type, platform, `${asset}.${FILE_EXTENSION}`, )); } diff --git a/src/models/Recipe.js b/src/models/Recipe.js index 106b4a56a..92ff0d67d 100644 --- a/src/models/Recipe.js +++ b/src/models/Recipe.js @@ -1,7 +1,7 @@ import emailParser from 'address-rfc2822'; import semver from 'semver'; -import fs from 'fs-extra'; -import path from 'path'; +import { pathExistsSync } from 'fs-extra'; +import { join } from 'path'; export default class Recipe { id = ''; @@ -98,6 +98,6 @@ export default class Recipe { } get hasDarkMode() { - return fs.pathExistsSync(path.join(this.path, 'darkmode.css')); + return pathExistsSync(join(this.path, 'darkmode.css')); } } diff --git a/src/models/Service.js b/src/models/Service.js index 79181186a..fe56e5a76 100644 --- a/src/models/Service.js +++ b/src/models/Service.js @@ -2,7 +2,7 @@ import { autorun, computed, observable } from 'mobx'; import { ipcRenderer } from 'electron'; import { webContents } from '@electron/remote'; import normalizeUrl from 'normalize-url'; -import path from 'path'; +import { join } from 'path'; import { todosStore } from '../features/todos'; import { isValidExternalURL } from '../helpers/url-helpers'; @@ -230,7 +230,7 @@ export default class Service { return this.iconUrl; } - return path.join(this.recipe.path, 'icon.svg'); + return join(this.recipe.path, 'icon.svg'); } @computed get hasCustomIcon() { diff --git a/src/scripts/add-crowdin-contributors.js b/src/scripts/add-crowdin-contributors.js index efe981b6e..ed29a0daf 100644 --- a/src/scripts/add-crowdin-contributors.js +++ b/src/scripts/add-crowdin-contributors.js @@ -58,7 +58,7 @@ const fs = require('fs-extra'); const path = require('path'); const allContributors = require('all-contributors-cli'); -const infoPath = path.join(__dirname, '../../.all-contributorsrc'); +const infoPath = path.join(__dirname, '..', '..', '.all-contributorsrc'); (async () => { const info = await fs.readJSON(infoPath); diff --git a/src/scripts/build-theme-info.js b/src/scripts/build-theme-info.js index cff33e3c4..4058be942 100644 --- a/src/scripts/build-theme-info.js +++ b/src/scripts/build-theme-info.js @@ -15,8 +15,8 @@ const accentColors = [ '#5e50ee', ]; -const cssFile = path.join(__dirname, '../../', 'build', 'styles', 'main.css'); -const outputFile = path.join(__dirname, '../', 'assets', 'themeInfo.json'); +const cssFile = path.join(__dirname, '..', '..', 'build', 'styles', 'main.css'); +const outputFile = path.join(__dirname, '..', 'assets', 'themeInfo.json'); // Parse and extract the rules from a CSS stylesheet file async function getRulesFromCssFile(file) { diff --git a/src/scripts/link-readme.js b/src/scripts/link-readme.js index 694b89700..1e47cddf8 100644 --- a/src/scripts/link-readme.js +++ b/src/scripts/link-readme.js @@ -11,7 +11,7 @@ const path = require('path'); console.log('Linking issues and PRs in README.md'); -const readmepath = path.join(__dirname, '../../', 'README.md'); +const readmepath = path.join(__dirname, '..', '..', 'README.md'); // Read README.md let readme = fs.readFileSync(readmepath, 'utf-8'); diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 6b5ca7c9a..1d706f1ef 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js @@ -12,7 +12,6 @@ import moment from 'moment'; import AutoLaunch from 'auto-launch'; import ms from 'ms'; import { URL } from 'url'; -import path from 'path'; import { readJsonSync } from 'fs-extra'; import Store from './lib/Store'; @@ -24,6 +23,7 @@ import { ferdiVersion, electronVersion, osRelease, + userDataPath, } from '../environment'; import locales from '../i18n/translations'; import { onVisibilityChange } from '../helpers/visibility-helper'; @@ -307,9 +307,7 @@ export default class AppStore extends Store { id: workspace.id, services: workspace.services, })), - windowSettings: readJsonSync( - path.join(app.getPath('userData'), 'window-state.json'), - ), + windowSettings: readJsonSync(userDataPath('window-state.json')), settings, features: this.stores.features.features, user: this.stores.user.data.id, diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.js index c7c4c1deb..d2acebb75 100644 --- a/src/stores/RecipesStore.js +++ b/src/stores/RecipesStore.js @@ -1,13 +1,12 @@ import { action, computed, observable } from 'mobx'; -import fs from 'fs-extra'; -import path from 'path'; +import { readJSONSync } from 'fs-extra'; import semver from 'semver'; import Store from './lib/Store'; import CachedRequest from './lib/CachedRequest'; import Request from './lib/Request'; import { matchRoute } from '../helpers/routing-helpers'; -import { RECIPES_PATH } from '../environment'; +import { asarRecipesPath } from '../environment'; const debug = require('debug')('Ferdi:RecipeStore'); @@ -90,8 +89,8 @@ export default class RecipesStore extends Store { const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)._promise; // Check for local updates - const allJsonFile = path.join(RECIPES_PATH, 'all.json'); - const allJson = await fs.readJSON(allJsonFile); + const allJsonFile = asarRecipesPath('all.json'); + const allJson = readJSONSync(allJsonFile); const localUpdates = []; Object.keys(recipes).forEach((recipe) => { diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 829797930..499495d08 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -3,8 +3,8 @@ import { action, reaction, computed, observable } from 'mobx'; import { debounce, remove } from 'lodash'; import ms from 'ms'; import { app } from '@electron/remote'; -import fs from 'fs-extra'; -import path from 'path'; +import { ensureFileSync, pathExistsSync, writeFileSync } from 'fs-extra'; +import { join } from 'path'; import Store from './lib/Store'; import Request from './lib/Request'; @@ -524,9 +524,9 @@ export default class ServicesStore extends Store { const devDirectory = getDevRecipeDirectory(recipe); let directory; - if (await fs.pathExists(normalDirectory)) { + if (pathExistsSync(normalDirectory)) { directory = normalDirectory; - } else if (await fs.pathExists(devDirectory)) { + } else if (pathExistsSync(devDirectory)) { directory = devDirectory; } else { // Recipe cannot be found on drive @@ -534,20 +534,19 @@ export default class ServicesStore extends Store { } // Create and open file - const filePath = path.join(directory, file); + const filePath = join(directory, file); if (file === 'user.js') { - if (!fs.existsSync(filePath)) { - await fs.writeFile( + if (!pathExistsSync(filePath)) { + writeFileSync( filePath, `module.exports = (config, Ferdi) => { // Write your scripts here console.log("Hello, World!", config); -} -`, - ); +}; +`); } } else { - await fs.ensureFile(filePath); + ensureFileSync(filePath); } shell.showItemInFolder(filePath); } diff --git a/src/webview/darkmode.js b/src/webview/darkmode.js index ab629435c..7435d6404 100644 --- a/src/webview/darkmode.js +++ b/src/webview/darkmode.js @@ -1,7 +1,7 @@ /* eslint no-bitwise: ["error", { "int32Hint": true }] */ -import path from 'path'; -import fs from 'fs-extra'; +import { join } from 'path'; +import { pathExistsSync, readFileSync } from 'fs-extra'; const debug = require('debug')('Ferdi:DarkMode'); @@ -10,9 +10,9 @@ const chars = [...'abcdefghijklmnopqrstuvwxyz']; const ID = [...Array(20)].map(() => chars[Math.random() * chars.length | 0]).join``; export function injectDarkModeStyle(recipePath) { - const darkModeStyle = path.join(recipePath, 'darkmode.css'); - if (fs.pathExistsSync(darkModeStyle)) { - const data = fs.readFileSync(darkModeStyle); + const darkModeStyle = join(recipePath, 'darkmode.css'); + if (pathExistsSync(darkModeStyle)) { + const data = readFileSync(darkModeStyle); const styles = document.createElement('style'); styles.id = ID; styles.innerHTML = data.toString(); diff --git a/src/webview/lib/RecipeWebview.js b/src/webview/lib/RecipeWebview.js index 305e79882..96caa125e 100644 --- a/src/webview/lib/RecipeWebview.js +++ b/src/webview/lib/RecipeWebview.js @@ -1,5 +1,5 @@ import { ipcRenderer } from 'electron'; -import { exists, pathExistsSync, readFile } from 'fs-extra'; +import { exists, pathExistsSync, readFileSync } from 'fs-extra'; const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); @@ -55,9 +55,8 @@ class RecipeWebview { injectCSS(...files) { files.forEach(async (file) => { if (pathExistsSync(file)) { - const data = await readFile(file, 'utf8'); const styles = document.createElement('style'); - styles.innerHTML = data; + styles.innerHTML = readFileSync(file, 'utf8'); document.querySelector('head').appendChild(styles); @@ -69,8 +68,7 @@ class RecipeWebview { injectJSUnsafe(...files) { Promise.all(files.map(async (file) => { if (await exists(file)) { - const data = await readFile(file, 'utf8'); - return data; + return readFileSync(file, 'utf8'); } debug('Script not found', file); return null; diff --git a/src/webview/recipe.js b/src/webview/recipe.js index 598c3eb9a..a45c34002 100644 --- a/src/webview/recipe.js +++ b/src/webview/recipe.js @@ -1,8 +1,8 @@ /* eslint-disable import/first */ import { contextBridge, ipcRenderer } from 'electron'; -import path from 'path'; +import { join } from 'path'; import { autorun, computed, observable } from 'mobx'; -import fs from 'fs-extra'; +import { pathExistsSync, readFileSync } from 'fs-extra'; import { debounce } from 'lodash'; // For some services darkreader tries to use the chrome extension message API @@ -189,7 +189,7 @@ class RecipeController { loadRecipeModule(event, config, recipe) { debug('loadRecipeModule'); - const modulePath = path.join(recipe.path, 'webview.js'); + const modulePath = join(recipe.path, 'webview.js'); debug('module path', modulePath); // Delete module from cache delete require.cache[require.resolve(modulePath)]; @@ -214,15 +214,15 @@ class RecipeController { const styles = document.createElement('style'); styles.innerHTML = screenShareCss; - const userCss = path.join(recipe.path, 'user.css'); - if (fs.existsSync(userCss)) { - const data = await fs.readFile(userCss); + const userCss = join(recipe.path, 'user.css'); + if (pathExistsSync(userCss)) { + const data = readFileSync(userCss); styles.innerHTML += data.toString(); } document.querySelector('head').appendChild(styles); - const userJs = path.join(recipe.path, 'user.js'); - if (fs.existsSync(userJs)) { + const userJs = join(recipe.path, 'user.js'); + if (pathExistsSync(userJs)) { const loadUserJs = () => { // eslint-disable-next-line const userJsModule = require(userJs); @@ -308,11 +308,11 @@ class RecipeController { debug('Enable dark mode'); // Check if recipe has a darkmode.css - const darkModeStyle = path.join( + const darkModeStyle = join( this.settings.service.recipe.path, 'darkmode.css', ); - const darkModeExists = fs.pathExistsSync(darkModeStyle); + const darkModeExists = pathExistsSync(darkModeStyle); debug('darkmode.css exists? ', darkModeExists ? 'Yes' : 'No'); -- cgit v1.2.3-54-g00ecf