From 574692551a27ea56660bf2061daeaa0d34beaff4 Mon Sep 17 00:00:00 2001 From: Shin'ya UEOKA Date: Sat, 5 Oct 2019 02:06:02 +0000 Subject: [PATCH] Make Properties class --- .../repositories/SettingRepository.ts | 4 +- src/background/usecases/CompletionsUseCase.ts | 4 +- src/background/usecases/parsers.ts | 4 +- .../components/form/PropertiesForm.tsx | 6 +- src/settings/components/index.tsx | 13 +-- src/shared/SettingData.ts | 15 +-- src/shared/Settings.ts | 37 +----- src/shared/properties.ts | 50 -------- src/shared/property-defs.ts | 56 --------- src/shared/settings/Properties.ts | 110 ++++++++++++++++++ .../components/form/PropertiesForm.test.tsx | 4 +- test/shared/SettingData.test.ts | 15 +-- test/shared/Settings.test.ts | 31 +---- test/shared/properties.test.js | 18 --- test/shared/property-defs.test.js | 18 --- test/shared/settings/Properties.test.ts | 30 +++++ 16 files changed, 179 insertions(+), 236 deletions(-) delete mode 100644 src/shared/properties.ts delete mode 100644 src/shared/property-defs.ts create mode 100644 src/shared/settings/Properties.ts delete mode 100644 test/shared/properties.test.js delete mode 100644 test/shared/property-defs.test.js create mode 100644 test/shared/settings/Properties.test.ts diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts index c7a0e84..a11b65f 100644 --- a/src/background/repositories/SettingRepository.ts +++ b/src/background/repositories/SettingRepository.ts @@ -1,7 +1,7 @@ import { injectable } from 'tsyringe'; import MemoryStorage from '../infrastructures/MemoryStorage'; import Settings, { valueOf, toJSON } from '../../shared/Settings'; -import * as PropertyDefs from '../../shared/property-defs'; +import Properties from '../../shared/settings/Properties'; const CACHED_SETTING_KEY = 'setting'; @@ -26,7 +26,7 @@ export default class SettingRepository { async setProperty( name: string, value: string | number | boolean, ): Promise { - let def = PropertyDefs.defs.find(d => name === d.name); + let def = Properties.def(name); if (!def) { throw new Error('unknown property: ' + name); } diff --git a/src/background/usecases/CompletionsUseCase.ts b/src/background/usecases/CompletionsUseCase.ts index 8cd4f32..bfff1e6 100644 --- a/src/background/usecases/CompletionsUseCase.ts +++ b/src/background/usecases/CompletionsUseCase.ts @@ -5,7 +5,7 @@ import CompletionsRepository from '../repositories/CompletionsRepository'; import * as filters from './filters'; import SettingRepository from '../repositories/SettingRepository'; import TabPresenter from '../presenters/TabPresenter'; -import * as PropertyDefs from '../../shared/property-defs'; +import Properties from '../../shared/settings/Properties'; const COMPLETION_ITEM_LIMIT = 10; @@ -129,7 +129,7 @@ export default class CompletionsUseCase { } querySet(name: string, keywords: string): Promise { - let items = PropertyDefs.defs.map((def) => { + let items = Properties.defs().map((def) => { if (def.type === 'boolean') { return [ { diff --git a/src/background/usecases/parsers.ts b/src/background/usecases/parsers.ts index 6135fd8..e8a1149 100644 --- a/src/background/usecases/parsers.ts +++ b/src/background/usecases/parsers.ts @@ -1,4 +1,4 @@ -import * as PropertyDefs from '../../shared//property-defs'; +import Properties from '../../shared/settings/Properties'; const mustNumber = (v: any): number => { let num = Number(v); @@ -16,7 +16,7 @@ const parseSetOption = ( value = !key.startsWith('no'); key = value ? key : key.slice(2); } - let def = PropertyDefs.defs.find(d => d.name === key); + let def = Properties.def(key); if (!def) { throw new Error('Unknown property: ' + key); } diff --git a/src/settings/components/form/PropertiesForm.tsx b/src/settings/components/form/PropertiesForm.tsx index ee98b7e..db8c8e5 100644 --- a/src/settings/components/form/PropertiesForm.tsx +++ b/src/settings/components/form/PropertiesForm.tsx @@ -18,7 +18,7 @@ class PropertiesForm extends React.Component { render() { let types = this.props.types; - let value = this.props.value; + let values = this.props.value; return
{ @@ -46,10 +46,10 @@ class PropertiesForm extends React.Component { {name}
; diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index ada6efb..e86d765 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -8,11 +8,11 @@ import BlacklistForm from './form/BlacklistForm'; import PropertiesForm from './form/PropertiesForm'; import * as settingActions from '../../settings/actions/setting'; import SettingData, { - JSONTextSettings, FormKeymaps, FormSearch, FormSettings, + FormKeymaps, FormSearch, FormSettings, JSONTextSettings, } from '../../shared/SettingData'; import { State as AppState } from '../reducers/setting'; import * as settings from '../../shared/Settings'; -import * as PropertyDefs from '../../shared/property-defs'; +import Properties from '../../shared/settings/Properties'; const DO_YOU_WANT_TO_CONTINUE = 'Some settings in JSON can be lost when migrating. ' + @@ -33,11 +33,6 @@ class SettingsComponent extends React.Component { } renderFormFields(form: any) { - let types = PropertyDefs.defs.reduce( - (o: {[key: string]: string}, def) => { - o[def.name] = def.type; - return o; - }, {}); return
Keybindings @@ -66,7 +61,7 @@ class SettingsComponent extends React.Component {
Properties { let data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithProperties( - settings.propertiesValueOf(value)), + Properties.fromJSON(value)) }); this.props.dispatch(settingActions.set(data)); } diff --git a/src/shared/SettingData.ts b/src/shared/SettingData.ts index 6605c80..aa4e382 100644 --- a/src/shared/SettingData.ts +++ b/src/shared/SettingData.ts @@ -2,6 +2,7 @@ import * as operations from './operations'; import Settings, * as settings from './Settings'; import Keymaps from './settings/Keymaps'; import Search from './settings/Search'; +import Properties from './settings/Properties'; export class FormKeymaps { private data: {[op: string]: string}; @@ -143,14 +144,14 @@ export class FormSettings { private search: FormSearch; - private properties: settings.Properties; + private properties: Properties; private blacklist: string[]; constructor( keymaps: FormKeymaps, search: FormSearch, - properties: settings.Properties, + properties: Properties, blacklist: string[], ) { this.keymaps = keymaps; @@ -177,7 +178,7 @@ export class FormSettings { ); } - buildWithProperties(props: settings.Properties): FormSettings { + buildWithProperties(props: Properties): FormSettings { return new FormSettings( this.keymaps, this.search, @@ -199,7 +200,7 @@ export class FormSettings { return settings.valueOf({ keymaps: this.keymaps.toKeymaps().toJSON(), search: this.search.toSearchSettings().toJSON(), - properties: this.properties, + properties: this.properties.toJSON(), blacklist: this.blacklist, }); } @@ -207,13 +208,13 @@ export class FormSettings { toJSON(): { keymaps: ReturnType; search: ReturnType; - properties: settings.Properties; + properties: ReturnType; blacklist: string[]; } { return { keymaps: this.keymaps.toJSON(), search: this.search.toJSON(), - properties: this.properties, + properties: this.properties.toJSON(), blacklist: this.blacklist, }; } @@ -227,7 +228,7 @@ export class FormSettings { return new FormSettings( FormKeymaps.valueOf(o.keymaps), FormSearch.valueOf(o.search), - settings.propertiesValueOf(o.properties), + Properties.fromJSON(o.properties), settings.blacklistValueOf(o.blacklist), ); } diff --git a/src/shared/Settings.ts b/src/shared/Settings.ts index e2bb3f4..6250aae 100644 --- a/src/shared/Settings.ts +++ b/src/shared/Settings.ts @@ -1,12 +1,6 @@ -import * as PropertyDefs from './property-defs'; import Keymaps from './settings/Keymaps'; import Search from './settings/Search'; - -export interface Properties { - hintchars: string; - smoothscroll: boolean; - complete: string; -} +import Properties from './settings/Properties'; export default interface Settings { keymaps: Keymaps; @@ -15,27 +9,6 @@ export default interface Settings { blacklist: string[]; } -export const propertiesValueOf = (o: any): Properties => { - let defNames = new Set(PropertyDefs.defs.map(def => def.name)); - let unknownName = Object.keys(o).find(name => !defNames.has(name)); - if (unknownName) { - throw new TypeError(`Unknown property name: "${unknownName}"`); - } - - for (let def of PropertyDefs.defs) { - if (!Object.prototype.hasOwnProperty.call(o, def.name)) { - continue; - } - if (typeof o[def.name] !== def.type) { - throw new TypeError(`property "${def.name}" is not ${def.type}`); - } - } - return { - ...PropertyDefs.defaultValues, - ...o, - }; -}; - export const blacklistValueOf = (o: any): string[] => { if (!Array.isArray(o)) { throw new TypeError(`"blacklist" is not an array of string`); @@ -59,7 +32,7 @@ export const valueOf = (o: any): Settings => { settings.search = Search.fromJSON(o.search); break; case 'properties': - settings.properties = propertiesValueOf(o.properties); + settings.properties = Properties.fromJSON(o.properties); break; case 'blacklist': settings.blacklist = blacklistValueOf(o.blacklist); @@ -75,7 +48,7 @@ export const toJSON = (settings: Settings): any => { return { keymaps: settings.keymaps.toJSON(), search: settings.search.toJSON(), - properties: settings.properties, + properties: settings.properties.toJSON(), blacklist: settings.blacklist, }; }; @@ -156,10 +129,10 @@ export const DefaultSetting: Settings = { 'wikipedia': 'https://en.wikipedia.org/w/index.php?search={}' } }), - properties: { + properties: Properties.fromJSON({ hintchars: 'abcdefghijklmnopqrstuvwxyz', smoothscroll: false, complete: 'sbh' - }, + }), blacklist: [] }; diff --git a/src/shared/properties.ts b/src/shared/properties.ts deleted file mode 100644 index 6315030..0000000 --- a/src/shared/properties.ts +++ /dev/null @@ -1,50 +0,0 @@ -export type Type = string | number | boolean; - -export class Def { - private name0: string; - - private description0: string; - - private defaultValue0: Type; - - constructor( - name: string, - description: string, - defaultValue: Type, - ) { - this.name0 = name; - this.description0 = description; - this.defaultValue0 = defaultValue; - } - - public get name(): string { - return this.name0; - } - - public get defaultValue(): Type { - return this.defaultValue0; - } - - public get description(): Type { - return this.description0; - } - - public get type(): string { - return typeof this.defaultValue; - } -} - -export const defs: Def[] = [ - new Def( - 'hintchars', - 'hint characters on follow mode', - 'abcdefghijklmnopqrstuvwxyz'), - new Def( - 'smoothscroll', - 'smooth scroll', - false), - new Def( - 'complete', - 'which are completed at the open page', - 'sbh'), -]; diff --git a/src/shared/property-defs.ts b/src/shared/property-defs.ts deleted file mode 100644 index fec9f80..0000000 --- a/src/shared/property-defs.ts +++ /dev/null @@ -1,56 +0,0 @@ -export type Type = string | number | boolean; - -export class Def { - private name0: string; - - private description0: string; - - private defaultValue0: Type; - - constructor( - name: string, - description: string, - defaultValue: Type, - ) { - this.name0 = name; - this.description0 = description; - this.defaultValue0 = defaultValue; - } - - public get name(): string { - return this.name0; - } - - public get defaultValue(): Type { - return this.defaultValue0; - } - - public get description(): Type { - return this.description0; - } - - public get type(): string { - return typeof this.defaultValue; - } -} - -export const defs: Def[] = [ - new Def( - 'hintchars', - 'hint characters on follow mode', - 'abcdefghijklmnopqrstuvwxyz'), - new Def( - 'smoothscroll', - 'smooth scroll', - false), - new Def( - 'complete', - 'which are completed at the open page', - 'sbh'), -]; - -export const defaultValues = { - hintchars: 'abcdefghijklmnopqrstuvwxyz', - smoothscroll: false, - complete: 'sbh', -}; diff --git a/src/shared/settings/Properties.ts b/src/shared/settings/Properties.ts new file mode 100644 index 0000000..1bc4c7f --- /dev/null +++ b/src/shared/settings/Properties.ts @@ -0,0 +1,110 @@ +export type PropertiesJSON = { + hintchars?: string; + smoothscroll?: boolean; + complete?: string; +}; + +export type PropertyTypes = { + hintchars: string; + smoothscroll: string; + complete: string; +}; + +type PropertyName = 'hintchars' | 'smoothscroll' | 'complete'; + +type PropertyDef = { + name: PropertyName; + description: string; + defaultValue: string | number | boolean; + type: 'string' | 'number' | 'boolean'; +}; + +const defs: PropertyDef[] = [ + { + name: 'hintchars', + description: 'hint characters on follow mode', + defaultValue: 'abcdefghijklmnopqrstuvwxyz', + type: 'string', + }, { + name: 'smoothscroll', + description: 'smooth scroll', + defaultValue: false, + type: 'boolean', + }, { + name: 'complete', + description: 'which are completed at the open page', + defaultValue: 'sbh', + type: 'string', + } +]; + +const defaultValues = { + hintchars: 'abcdefghijklmnopqrstuvwxyz', + smoothscroll: false, + complete: 'sbh', +}; + +export default class Properties { + public hintchars: string; + + public smoothscroll: boolean; + + public complete: string; + + constructor({ + hintchars, + smoothscroll, + complete, + }: { + hintchars?: string; + smoothscroll?: boolean; + complete?: string; + }) { + this.hintchars = hintchars || defaultValues.hintchars; + this.smoothscroll = smoothscroll || defaultValues.smoothscroll; + this.complete = complete || defaultValues.complete; + } + + static fromJSON(json: any): Properties { + let defNames: Set = new Set(defs.map(def => def.name)); + let unknownName = Object.keys(json).find(name => !defNames.has(name)); + if (unknownName) { + throw new TypeError(`Unknown property name: "${unknownName}"`); + } + + for (let def of defs) { + if (!Object.prototype.hasOwnProperty.call(json, def.name)) { + continue; + } + if (typeof json[def.name] !== def.type) { + throw new TypeError( + `property "${def.name}" is not ${def.type}`); + } + } + return new Properties(json); + } + + static types(): PropertyTypes { + return { + hintchars: 'string', + smoothscroll: 'boolean', + complete: 'string', + }; + } + + static def(name: string): PropertyDef | undefined { + return defs.find(p => p.name === name); + } + + static defs(): PropertyDef[] { + return defs; + } + + toJSON(): PropertiesJSON { + return { + hintchars: this.hintchars, + smoothscroll: this.smoothscroll, + complete: this.complete, + }; + } +} diff --git a/test/settings/components/form/PropertiesForm.test.tsx b/test/settings/components/form/PropertiesForm.test.tsx index 80f60d2..0e33cc8 100644 --- a/test/settings/components/form/PropertiesForm.test.tsx +++ b/test/settings/components/form/PropertiesForm.test.tsx @@ -13,14 +13,14 @@ describe("settings/form/PropertiesForm", () => { mybool: 'boolean', empty: 'string', } - let value = { + let values = { mystr: 'abc', mynum: 123, mybool: true, }; let root = ReactTestRenderer.create( - , + , ).root let input = root.findByProps({ name: 'mystr' }); diff --git a/test/shared/SettingData.test.ts b/test/shared/SettingData.test.ts index f8995d9..b5bf70e 100644 --- a/test/shared/SettingData.test.ts +++ b/test/shared/SettingData.test.ts @@ -5,6 +5,7 @@ import Settings from '../../src/shared/Settings'; import { expect } from 'chai'; import Keymaps from '../../src/shared/settings/Keymaps'; import Search from '../../src/shared/settings/Search'; +import Properties from '../../src/shared/settings/Properties'; describe('shared/SettingData', () => { describe('FormKeymaps', () => { @@ -62,7 +63,7 @@ describe('shared/SettingData', () => { expect({ keymaps: settings.keymaps.toJSON(), search: settings.search.toJSON(), - properties: settings.properties, + properties: settings.properties.toJSON(), blacklist: settings.blacklist, }).to.deep.equal(JSON.parse(o)); }); @@ -78,11 +79,11 @@ describe('shared/SettingData', () => { google: "https://google.com/search?q={}", }, }), - properties: { + properties: Properties.fromJSON({ hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, complete: "sbh" - }, + }), blacklist: [], }; @@ -90,7 +91,7 @@ describe('shared/SettingData', () => { expect(JSON.parse(json)).to.deep.equal({ keymaps: o.keymaps.toJSON(), search: o.search.toJSON(), - properties: o.properties, + properties: o.properties.toJSON(), blacklist: o.blacklist, }); }); @@ -123,7 +124,7 @@ describe('shared/SettingData', () => { expect({ keymaps: settings.keymaps.toJSON(), search: settings.search.toJSON(), - properties: settings.properties, + properties: settings.properties.toJSON(), blacklist: settings.blacklist, }).to.deep.equal({ keymaps: { @@ -159,11 +160,11 @@ describe('shared/SettingData', () => { "google": "https://google.com/search?q={}" } }), - properties: { + properties: Properties.fromJSON({ hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, complete: "sbh" - }, + }), blacklist: [] }; diff --git a/test/shared/Settings.test.ts b/test/shared/Settings.test.ts index ed791a1..6360bab 100644 --- a/test/shared/Settings.test.ts +++ b/test/shared/Settings.test.ts @@ -1,33 +1,8 @@ import * as settings from '../../src/shared/Settings'; -import { expect } from 'chai'; +import {expect} from 'chai'; describe('Settings', () => { - describe('#propertiesValueOf', () => { - it('returns with default properties by empty settings', () => { - let props = settings.propertiesValueOf({}); - expect(props).to.deep.equal({ - hintchars: "abcdefghijklmnopqrstuvwxyz", - smoothscroll: false, - complete: "sbh" - }) - }); - - it('returns properties by valid settings', () => { - let props = settings.propertiesValueOf({ - hintchars: "abcdefgh", - smoothscroll: false, - complete: "sbh" - }); - - expect(props).to.deep.equal({ - hintchars: "abcdefgh", - smoothscroll: false, - complete: "sbh" - }); - }); - }); - describe('#blacklistValueOf', () => { it('returns empty array by empty settings', () => { let blacklist = settings.blacklistValueOf([]); @@ -70,7 +45,7 @@ describe('Settings', () => { expect({ keymaps: x.keymaps.toJSON(), search: x.search.toJSON(), - properties: x.properties, + properties: x.properties.toJSON(), blacklist: x.blacklist, }).to.deep.equal({ keymaps: {}, @@ -92,7 +67,7 @@ describe('Settings', () => { it('sets default settings', () => { let value = settings.valueOf({}); expect(value.keymaps.toJSON()).to.not.be.empty; - expect(value.properties).to.not.be.empty; + expect(value.properties.toJSON()).to.not.be.empty; expect(value.search.defaultEngine).to.be.a('string'); expect(value.search.engines).to.be.an('object'); expect(value.blacklist).to.be.empty; diff --git a/test/shared/properties.test.js b/test/shared/properties.test.js deleted file mode 100644 index 37903d8..0000000 --- a/test/shared/properties.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as settings from 'shared/settings'; - -describe('properties', () => { - describe('Def class', () => { - it('returns property definitions', () => { - let def = new proerties.Def( - 'smoothscroll', - 'smooth scroll', - false); - - expect(def.name).to.equal('smoothscroll'); - expect(def.describe).to.equal('smooth scroll'); - expect(def.defaultValue).to.equal(false); - expect(def.type).to.equal('boolean'); - }); - }); -}); - diff --git a/test/shared/property-defs.test.js b/test/shared/property-defs.test.js deleted file mode 100644 index 37903d8..0000000 --- a/test/shared/property-defs.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as settings from 'shared/settings'; - -describe('properties', () => { - describe('Def class', () => { - it('returns property definitions', () => { - let def = new proerties.Def( - 'smoothscroll', - 'smooth scroll', - false); - - expect(def.name).to.equal('smoothscroll'); - expect(def.describe).to.equal('smooth scroll'); - expect(def.defaultValue).to.equal(false); - expect(def.type).to.equal('boolean'); - }); - }); -}); - diff --git a/test/shared/settings/Properties.test.ts b/test/shared/settings/Properties.test.ts new file mode 100644 index 0000000..609a565 --- /dev/null +++ b/test/shared/settings/Properties.test.ts @@ -0,0 +1,30 @@ +import Properties from '../../../src/shared/settings/Properties'; +import { expect } from 'chai'; + +describe('Properties', () => { + describe('#propertiesValueOf', () => { + it('returns with default properties by empty settings', () => { + let props = Properties.fromJSON({}); + expect(props).to.deep.equal({ + hintchars: "abcdefghijklmnopqrstuvwxyz", + smoothscroll: false, + complete: "sbh" + }) + }); + + it('returns properties by valid settings', () => { + let props = Properties.fromJSON({ + hintchars: "abcdefgh", + smoothscroll: false, + complete: "sbh" + }); + + expect(props).to.deep.equal({ + hintchars: "abcdefgh", + smoothscroll: false, + complete: "sbh" + }); + }); + }); +}); +