Chore: Increase strength of `Setting`s types (#10605)

pull/10658/head
Henry Heino 2024-06-25 06:01:39 -07:00 committed by GitHub
parent c7116b135f
commit a44412ae78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 1747 additions and 1690 deletions

View File

@ -941,8 +941,10 @@ packages/lib/models/Tag.test.js
packages/lib/models/Tag.js
packages/lib/models/dateTimeFormats.test.js
packages/lib/models/settings/FileHandler.js
packages/lib/models/settings/builtInMetadata.js
packages/lib/models/settings/settingValidations.test.js
packages/lib/models/settings/settingValidations.js
packages/lib/models/settings/types.js
packages/lib/models/utils/getCollator.js
packages/lib/models/utils/getConflictFolderId.js
packages/lib/models/utils/isItemId.js

2
.gitignore vendored
View File

@ -920,8 +920,10 @@ packages/lib/models/Tag.test.js
packages/lib/models/Tag.js
packages/lib/models/dateTimeFormats.test.js
packages/lib/models/settings/FileHandler.js
packages/lib/models/settings/builtInMetadata.js
packages/lib/models/settings/settingValidations.test.js
packages/lib/models/settings/settingValidations.js
packages/lib/models/settings/types.js
packages/lib/models/utils/getCollator.js
packages/lib/models/utils/getConflictFolderId.js
packages/lib/models/utils/isItemId.js

View File

@ -1,4 +1,4 @@
import Setting, { SettingStorage } from '@joplin/lib/models/Setting';
import Setting, { AppType, SettingStorage } from '@joplin/lib/models/Setting';
import { SettingItemType } from '@joplin/lib/services/plugins/api/types';
import shim from '@joplin/lib/shim';
@ -61,7 +61,7 @@ class Command extends BaseCommand {
const description: string[] = [];
if (md.label && md.label()) description.push(md.label());
if (md.description && md.description('desktop')) description.push(md.description('desktop'));
if (md.description && md.description(AppType.Desktop)) description.push(md.description(AppType.Desktop));
if (description.length) props.description = description.join('. ');
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied

View File

@ -405,7 +405,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
return (
<div key={key} style={rowStyle}>
{label}
{this.renderDescription(this.props.themeId, md.description ? md.description() : null)}
{this.renderDescription(this.props.themeId, md.description ? md.description(AppType.Desktop) : null)}
<SettingComponent
metadata={md}
value={value}
@ -667,7 +667,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
};
const label = [md.label()];
if (md.unitLabel) label.push(`(${md.unitLabel()})`);
if (md.unitLabel) label.push(`(${md.unitLabel(md.value)})`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
const inputStyle: any = { ...textInputBaseStyle };

View File

@ -713,7 +713,7 @@ function useMenu(props: Props) {
label: layoutButtonSequenceOptions[value],
type: 'checkbox',
click: () => {
Setting.setValue('layoutButtonSequence', value);
Setting.setValue('layoutButtonSequence', Number(value));
},
});
}

View File

@ -60,7 +60,8 @@ export const setNotesSortOrder = (field?: string, reverse?: boolean) => {
nextReverse = !!nextReverse;
if (perFieldReverse[nextField] !== nextReverse) {
perFieldReverse[nextField] = nextReverse;
Setting.setValue('notes.perFieldReverse', { ...perFieldReverse });
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code before rule was applied
Setting.setValue('notes.perFieldReverse', { ...perFieldReverse } as any);
}
}
};

View File

@ -1,4 +1,4 @@
import Setting from '@joplin/lib/models/Setting';
import Setting, { AppType } from '@joplin/lib/models/Setting';
import bridge from '../bridge';
import processStartFlags from '@joplin/lib/utils/processStartFlags';
import { safeModeFlagFilename } from '@joplin/lib/BaseApplication';
@ -13,7 +13,7 @@ const restartInSafeModeFromMain = async () => {
// a large amount of other code) to the database.
const appName = bridge().appName();
Setting.setConstant('appId', `net.cozic.${appName}`);
Setting.setConstant('appType', 'desktop');
Setting.setConstant('appType', AppType.Desktop);
Setting.setConstant('appName', appName);
// Load just enough for us to write a file in the profile directory

View File

@ -50,7 +50,7 @@ interface Props {
}
function fontFamilyFromSettings() {
const font = editorFont(Setting.value('style.editor.fontFamily'));
const font = editorFont(Setting.value('style.editor.fontFamily') as number);
return font ? `${font}, sans-serif` : 'sans-serif';
}

View File

@ -475,7 +475,7 @@ class ConfigScreenComponent extends BaseScreenComponent<ConfigScreenProps, Confi
}
const settingComp = this.settingToComponent(md.key, settings[md.key]);
const relatedText = [md.label?.() ?? '', md.description?.() ?? ''];
const relatedText = [md.label?.() ?? '', md.description?.(AppType.Mobile) ?? ''];
addSettingComponent(
settingComp,
relatedText,

View File

@ -2,7 +2,7 @@ import * as React from 'react';
import { UpdateSettingValueCallback } from './types';
import { View, Text, TextInput } from 'react-native';
import Setting from '@joplin/lib/models/Setting';
import Setting, { AppType } from '@joplin/lib/models/Setting';
import Dropdown from '../../Dropdown';
import { ConfigScreenStyles } from './configScreenStyles';
import Slider from '@react-native-community/slider';
@ -32,7 +32,7 @@ const SettingComponent: React.FunctionComponent<Props> = props => {
const output: any = null;
const md = Setting.settingMetadata(props.settingId);
const settingDescription = md.description ? md.description() : '';
const settingDescription = md.description ? md.description(AppType.Mobile) : '';
const styleSheet = props.styles.styleSheet;

View File

@ -14,7 +14,7 @@ import ResourceService from '@joplin/lib/services/ResourceService';
import KvStore from '@joplin/lib/services/KvStore';
import NoteScreen from './components/screens/Note';
import UpgradeSyncTargetScreen from './components/screens/UpgradeSyncTargetScreen';
import Setting, { Env } from '@joplin/lib/models/Setting';
import Setting, { AppType, Env } from '@joplin/lib/models/Setting';
import PoorManIntervals from '@joplin/lib/PoorManIntervals';
import reducer, { NotesParent, parseNotesParent, serializeNotesParent } from '@joplin/lib/reducer';
import ShareExtension from './utils/ShareExtension';
@ -505,9 +505,9 @@ async function initialize(dispatch: Function) {
value: profileConfig,
});
Setting.setConstant('env', __DEV__ ? 'dev' : 'prod');
Setting.setConstant('env', __DEV__ ? Env.Dev : Env.Prod);
Setting.setConstant('appId', 'net.cozic.joplin-mobile');
Setting.setConstant('appType', 'mobile');
Setting.setConstant('appType', AppType.Mobile);
Setting.setConstant('tempDir', await initializeTempDir());
Setting.setConstant('cacheDir', `${getProfilesRootDir()}/cache`);
const resourceDir = getResourceDir(currentProfile, isSubProfile);
@ -619,7 +619,7 @@ async function initialize(dispatch: Function) {
reg.logger().info(`First start: detected locale as ${detectedLocale}`);
Setting.skipDefaultMigrations();
Setting.setValue('firstStart', 0);
Setting.setValue('firstStart', false);
} else {
Setting.applyDefaultMigrations();
}
@ -788,7 +788,7 @@ async function initialize(dispatch: Function) {
const pluginSettings = pluginService.unserializePluginSettings(Setting.value('plugins.states'));
const updatedSettings = pluginService.clearUpdateState(pluginSettings);
Setting.setValue('plugins.states', pluginService.serializePluginSettings(updatedSettings));
Setting.setValue('plugins.states', updatedSettings);
// ----------------------------------------------------------------------------
// Keep this below to test react-native-rsa-native

View File

@ -3,7 +3,7 @@
"packageManager": "yarn@3.6.0",
"private": true,
"scripts": {
"buildPluginDoc_": "typedoc --name 'Joplin Plugin API Documentation' --mode file -theme '../../Assets/PluginDocTheme/' --readme '../../Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out ../../../joplin-website/docs/api/references/plugin_api ../lib/services/plugins/api/"
"buildPluginDoc_": "typedoc --exclude '../lib/models/**' --name 'Joplin Plugin API Documentation' --mode file -theme '../../Assets/PluginDocTheme/' --readme '../../Assets/PluginDocTheme/index.md' --excludeNotExported --excludeExternals --excludePrivate --excludeProtected --out ../../../joplin-website/docs/api/references/plugin_api ../lib/services/plugins/api/"
},
"dependencies": {
"typedoc": "0.17.8",

View File

@ -687,7 +687,7 @@ export default class BaseApplication {
const tempDir = `${profileDir}/tmp`;
const cacheDir = `${profileDir}/cache`;
Setting.setConstant('env', initArgs.env);
Setting.setConstant('env', initArgs.env as Env);
Setting.setConstant('resourceDirName', resourceDirName);
Setting.setConstant('resourceDir', resourceDir);
Setting.setConstant('tempDir', tempDir);
@ -789,12 +789,12 @@ export default class BaseApplication {
Setting.skipDefaultMigrations();
if (Setting.value('env') === 'dev') {
Setting.setValue('showTrayIcon', 0);
Setting.setValue('autoUpdateEnabled', 0);
Setting.setValue('showTrayIcon', false);
Setting.setValue('autoUpdateEnabled', false);
Setting.setValue('sync.interval', 3600);
}
Setting.setValue('firstStart', 0);
Setting.setValue('firstStart', false);
} else {
Setting.applyDefaultMigrations();
Setting.applyUserSettingMigration();

View File

@ -5,6 +5,7 @@ import Logger from '@joplin/utils/Logger';
import { defaultProfileConfig } from '../services/profileConfig/types';
import { createNewProfile, saveProfileConfig } from '../services/profileConfig';
import initProfile from '../services/profileConfig/initProfile';
import { defaultPluginSetting } from '../services/plugins/PluginService';
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
async function loadSettingsFromFile(): Promise<any> {
@ -206,7 +207,7 @@ describe('models/Setting', () => {
it('should save and load settings from file', (async () => {
Setting.setValue('sync.target', 9); // Saved to file
Setting.setValue('encryption.passwordCache', {}); // Saved to keychain or db
Setting.setValue('plugins.states', { test: true }); // Always saved to db
Setting.setValue('plugins.states', { test: defaultPluginSetting() }); // Always saved to db
await Setting.saveAll();
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,108 @@
import type { BuiltInMetadataValues } from './builtInMetadata';
export enum SettingItemType {
Int = 1,
String = 2,
Bool = 3,
Array = 4,
Object = 5,
Button = 6,
}
export enum SettingItemSubType {
FilePathAndArgs = 'file_path_and_args',
FilePath = 'file_path', // Not supported on mobile!
DirectoryPath = 'directory_path', // Not supported on mobile!
FontFamily = 'font_family',
MonospaceFontFamily = 'monospace_font_family',
}
export enum SettingStorage {
Database = 1,
File = 2,
}
// This is the definition of a setting item
export interface SettingItem {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
type: SettingItemType;
public: boolean;
subType?: string;
key?: string;
isEnum?: boolean;
section?: string;
label?(): string;
description?: (_appType: AppType)=> string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options?(): any;
optionsOrder?(): string[];
appTypes?: AppType[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
show?(settings: any): boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
filter?(value: any): any;
secure?: boolean;
advanced?: boolean;
minimum?: number;
maximum?: number;
step?: number;
onClick?(): void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partially refactored old code before rule was applied
unitLabel?: (value: any)=> string;
needRestart?: boolean;
autoSave?: boolean;
storage?: SettingStorage;
hideLabel?: boolean;
// In a multi-profile context, all settings are by default local - they take
// their value from the current profile. This flag can be set to specify
// that the setting is global and that its value should come from the root
// profile. This flag only applies to sub-profiles.
//
// At the moment, all global settings must be saved to file (have the
// storage attribute set to "file") because it's simpler to load the root
// profile settings.json than load the whole SQLite database. This
// restriction is not an issue normally since all settings that are
// considered global are also the user-facing ones.
isGlobal?: boolean;
}
export interface SettingItems {
[key: string]: SettingItem;
}
export enum SettingSectionSource {
Default = 1,
Plugin = 2,
}
export interface SettingSection {
label: string;
iconName?: string;
description?: string;
name?: string;
source?: SettingSectionSource;
}
export enum SyncStartupOperation {
None = 0,
ClearLocalSyncState = 1,
ClearLocalData = 2,
}
export enum Env {
Undefined = 'SET_ME',
Dev = 'dev',
Prod = 'prod',
}
export enum AppType {
Desktop = 'desktop',
Mobile = 'mobile',
Cli = 'cli',
}
export type SettingsRecord = BuiltInMetadataValues & { [key: string]: unknown };

View File

@ -12,6 +12,7 @@ import { getListRendererIds } from './services/noteList/renderers';
import { ProcessResultsRow } from './services/search/SearchEngine';
import { getDisplayParentId } from './services/trash';
import Logger from '@joplin/utils/Logger';
import { SettingsRecord } from './models/settings/types';
const fastDeepEqual = require('fast-deep-equal');
const { ALL_NOTES_FILTER_ID } = require('./reserved-ids');
const { createSelectorCreator, defaultMemoize } = require('reselect');
@ -100,8 +101,7 @@ export interface State {
syncReport: any;
searchQuery: string;
searchResults: ProcessResultsRow[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
settings: Record<string, any>;
settings: Partial<SettingsRecord>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
sharedData: any;
appState: string;

View File

@ -1,4 +1,4 @@
import Setting from './models/Setting';
import Setting, { Env } from './models/Setting';
import { reg } from './registry';
const sync = {
@ -9,7 +9,7 @@ describe('Registry', () => {
let originalSyncTarget: typeof reg.syncTarget;
beforeAll(() => {
Setting.setConstant('env', 'prod');
Setting.setConstant('env', Env.Prod);
originalSyncTarget = reg.syncTarget;
reg.syncTarget = () => ({
isAuthenticated: () => true,
@ -18,7 +18,7 @@ describe('Registry', () => {
});
afterAll(() => {
Setting.setConstant('env', 'dev');
Setting.setConstant('env', Env.Dev);
reg.syncTarget = originalSyncTarget;
});

View File

@ -215,8 +215,8 @@ export default class PluginService extends BaseService {
return output as PluginSettings;
}
public serializePluginSettings(settings: PluginSettings): string {
return JSON.stringify(settings);
public serializePluginSettings(settings: PluginSettings) {
return settings;
}
public pluginIdByContentScriptId(contentScriptId: string): string {

View File

@ -2,7 +2,7 @@
import BaseApplication from '../BaseApplication';
import BaseModel from '../BaseModel';
import Logger, { TargetType, LoggerWrapper, LogLevel } from '@joplin/utils/Logger';
import Setting from '../models/Setting';
import Setting, { AppType, Env } from '../models/Setting';
import BaseService from '../services/BaseService';
import FsDriverNode from '../fs-driver-node';
import time from '../time';
@ -190,14 +190,14 @@ BaseItem.loadClass('MasterKey', MasterKey);
BaseItem.loadClass('Revision', Revision);
Setting.setConstant('appId', 'net.cozic.joplintest-cli');
Setting.setConstant('appType', 'cli');
Setting.setConstant('appType', AppType.Cli);
Setting.setConstant('tempDir', baseTempDir);
Setting.setConstant('cacheDir', baseTempDir);
Setting.setConstant('resourceDir', baseTempDir);
Setting.setConstant('pluginDataDir', `${profileDir}/profile/plugin-data`);
Setting.setConstant('profileDir', profileDir);
Setting.setConstant('rootProfileDir', rootProfileDir);
Setting.setConstant('env', 'dev');
Setting.setConstant('env', Env.Dev);
BaseService.logger_ = logger;
@ -640,7 +640,7 @@ async function initFileApi() {
mustRunInBand();
const { parameters, setEnvOverride } = require('../parameters.js');
Setting.setConstant('env', 'dev');
Setting.setConstant('env', Env.Dev);
setEnvOverride('test');
const config = parameters().oneDriveTest;
const api = new OneDriveApi(config.id, config.secret, false);