From 410ffbb0376b9399928ef8d4dd13079bfb120e14 Mon Sep 17 00:00:00 2001 From: Shin'ya UEOKA Date: Fri, 4 Oct 2019 04:01:35 +0000 Subject: Make Keymap class --- test/shared/Settings.test.ts | 45 ++++++++------------------------------------ 1 file changed, 8 insertions(+), 37 deletions(-) (limited to 'test/shared/Settings.test.ts') diff --git a/test/shared/Settings.test.ts b/test/shared/Settings.test.ts index 04b28c4..9faf9d1 100644 --- a/test/shared/Settings.test.ts +++ b/test/shared/Settings.test.ts @@ -1,31 +1,7 @@ import * as settings from '../../src/shared/Settings'; -import { expect } from 'chai'; +import {expect} from 'chai'; describe('Settings', () => { - describe('#keymapsValueOf', () => { - it('returns empty object by empty settings', () => { - let keymaps = settings.keymapsValueOf({}); - expect(keymaps).to.be.empty; - }); - - it('returns keymaps by valid settings', () => { - let keymaps = settings.keymapsValueOf({ - k: { type: "scroll.vertically", count: -1 }, - j: { type: "scroll.vertically", count: 1 }, - }); - - expect(keymaps['k']).to.deep.equal({ type: "scroll.vertically", count: -1 }); - expect(keymaps['j']).to.deep.equal({ type: "scroll.vertically", count: 1 }); - }); - - it('throws a TypeError by invalid settings', () => { - expect(() => settings.keymapsValueOf(null)).to.throw(TypeError); - expect(() => settings.keymapsValueOf({ - k: { type: "invalid.operation" }, - })).to.throw(TypeError); - }); - }); - describe('#searchValueOf', () => { it('returns search settings by valid settings', () => { let search = settings.searchValueOf({ @@ -110,16 +86,6 @@ describe('Settings', () => { complete: "sbh" }); }); - - it('throws a TypeError by invalid settings', () => { - expect(() => settings.keymapsValueOf(null)).to.throw(TypeError); - expect(() => settings.keymapsValueOf({ - smoothscroll: 'false', - })).to.throw(TypeError); - expect(() => settings.keymapsValueOf({ - unknown: 'xyz' - })).to.throw(TypeError); - }); }); describe('#blacklistValueOf', () => { @@ -161,7 +127,12 @@ describe('Settings', () => { "blacklist": [] }); - expect(x).to.deep.equal({ + expect({ + keymaps: x.keymaps.toJSON(), + search: x.search, + properties: x.properties, + blacklist: x.blacklist, + }).to.deep.equal({ keymaps: {}, search: { default: "google", @@ -180,7 +151,7 @@ describe('Settings', () => { it('sets default settings', () => { let value = settings.valueOf({}); - expect(value.keymaps).to.not.be.empty; + expect(value.keymaps.toJSON()).to.not.be.empty; expect(value.properties).to.not.be.empty; expect(value.search.default).to.be.a('string'); expect(value.search.engines).to.be.an('object'); -- cgit v1.2.3 From 2116ac90a6dfdb0910d7ad2896f70a052aa635cc Mon Sep 17 00:00:00 2001 From: Shin'ya UEOKA Date: Sat, 5 Oct 2019 01:08:07 +0000 Subject: Make Search class --- src/shared/SettingData.ts | 22 +++---- src/shared/Settings.ts | 44 ++----------- src/shared/settings/Search.ts | 76 ++++++++++++++++++++++ src/shared/urls.ts | 4 +- .../content/repositories/SettingRepository.test.ts | 5 +- test/shared/SettingData.test.ts | 19 +++--- test/shared/Settings.test.ts | 66 +------------------ test/shared/settings/Search.test.ts | 68 +++++++++++++++++++ test/shared/urls.test.ts | 8 ++- 9 files changed, 182 insertions(+), 130 deletions(-) create mode 100644 src/shared/settings/Search.ts create mode 100644 test/shared/settings/Search.test.ts (limited to 'test/shared/Settings.test.ts') diff --git a/src/shared/SettingData.ts b/src/shared/SettingData.ts index eb83b75..6605c80 100644 --- a/src/shared/SettingData.ts +++ b/src/shared/SettingData.ts @@ -1,6 +1,7 @@ import * as operations from './operations'; import Settings, * as settings from './Settings'; import Keymaps from './settings/Keymaps'; +import Search from './settings/Search'; export class FormKeymaps { private data: {[op: string]: string}; @@ -71,15 +72,12 @@ export class FormSearch { this.engines = engines; } - toSearchSettings(): settings.Search { - return { - default: this.default, - engines: this.engines.reduce( - (o: {[key: string]: string}, [name, url]) => { - o[name] = url; - return o; - }, {}), - }; + toSearchSettings(): Search { + let engines: { [name: string]: string } = {}; + for (let entry of this.engines) { + engines[entry[0]] = entry[1]; + } + return new Search(this.default, engines); } toJSON(): { @@ -102,12 +100,12 @@ export class FormSearch { return new FormSearch(o.default, o.engines); } - static fromSearch(search: settings.Search): FormSearch { + static fromSearch(search: Search): FormSearch { let engines = Object.entries(search.engines).reduce( (o: string[][], [name, url]) => { return o.concat([[name, url]]); }, []); - return new FormSearch(search.default, engines); + return new FormSearch(search.defaultEngine, engines); } } @@ -200,7 +198,7 @@ export class FormSettings { toSettings(): Settings { return settings.valueOf({ keymaps: this.keymaps.toKeymaps().toJSON(), - search: this.search.toSearchSettings(), + search: this.search.toSearchSettings().toJSON(), properties: this.properties, blacklist: this.blacklist, }); diff --git a/src/shared/Settings.ts b/src/shared/Settings.ts index 3014abc..e2bb3f4 100644 --- a/src/shared/Settings.ts +++ b/src/shared/Settings.ts @@ -1,10 +1,6 @@ import * as PropertyDefs from './property-defs'; import Keymaps from './settings/Keymaps'; - -export interface Search { - default: string; - engines: { [key: string]: string }; -} +import Search from './settings/Search'; export interface Properties { hintchars: string; @@ -19,36 +15,6 @@ export default interface Settings { blacklist: string[]; } -export const searchValueOf = (o: any): Search => { - if (typeof o.default !== 'string') { - throw new TypeError('string field "default" not set"'); - } - for (let name of Object.keys(o.engines)) { - if ((/\s/).test(name)) { - throw new TypeError( - `While space in the search engine not allowed: "${name}"`); - } - let url = o.engines[name]; - if (typeof url !== 'string') { - throw new TypeError('"engines" not an object of string'); - } - let matches = url.match(/{}/g); - if (matches === null) { - throw new TypeError(`No {}-placeholders in URL of "${name}"`); - } else if (matches.length > 1) { - throw new TypeError(`Multiple {}-placeholders in URL of "${name}"`); - } - - } - if (!Object.prototype.hasOwnProperty.call(o.engines, o.default)) { - throw new TypeError(`Default engine "${o.default}" not found`); - } - return { - default: o.default as string, - engines: { ...o.engines }, - }; -}; - 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)); @@ -90,7 +56,7 @@ export const valueOf = (o: any): Settings => { settings.keymaps = Keymaps.fromJSON(o.keymaps); break; case 'search': - settings.search = searchValueOf(o.search); + settings.search = Search.fromJSON(o.search); break; case 'properties': settings.properties = propertiesValueOf(o.properties); @@ -108,7 +74,7 @@ export const valueOf = (o: any): Settings => { export const toJSON = (settings: Settings): any => { return { keymaps: settings.keymaps.toJSON(), - search: settings.search, + search: settings.search.toJSON(), properties: settings.properties, blacklist: settings.blacklist, }; @@ -179,7 +145,7 @@ export const DefaultSetting: Settings = { '.': { 'type': 'repeat.last' }, '': { 'type': 'addon.toggle.enabled' } }), - search: { + search: Search.fromJSON({ default: 'google', engines: { 'google': 'https://google.com/search?q={}', @@ -189,7 +155,7 @@ export const DefaultSetting: Settings = { 'twitter': 'https://twitter.com/search?q={}', 'wikipedia': 'https://en.wikipedia.org/w/index.php?search={}' } - }, + }), properties: { hintchars: 'abcdefghijklmnopqrstuvwxyz', smoothscroll: false, diff --git a/src/shared/settings/Search.ts b/src/shared/settings/Search.ts new file mode 100644 index 0000000..4580236 --- /dev/null +++ b/src/shared/settings/Search.ts @@ -0,0 +1,76 @@ +type Entries = { [name: string]: string }; + +export type SearchJSON = { + default: string; + engines: { [key: string]: string }; +}; + +export default class Search { + constructor( + public defaultEngine: string, + public engines: Entries, + ) { + } + + static fromJSON(json: any): Search { + let defaultEngine = Search.getStringField(json, 'default'); + let engines = Search.getObjectField(json, 'engines'); + + for (let [name, url] of Object.entries(engines)) { + if ((/\s/).test(name)) { + throw new TypeError( + `While space in the search engine not allowed: "${name}"`); + } + if (typeof url !== 'string') { + throw new TypeError( + `Invalid type of value in filed "engines": ${JSON.stringify(json)}`); + } + let matches = url.match(/{}/g); + if (matches === null) { + throw new TypeError(`No {}-placeholders in URL of "${name}"`); + } else if (matches.length > 1) { + throw new TypeError(`Multiple {}-placeholders in URL of "${name}"`); + } + } + + if (!Object.keys(engines).includes(defaultEngine)) { + throw new TypeError(`Default engine "${defaultEngine}" not found`); + } + + return new Search( + json.default as string, + json.engines, + ); + } + + toJSON(): SearchJSON { + return { + default: this.defaultEngine, + engines: this.engines, + }; + } + + private static getStringField(json: any, name: string): string { + if (!Object.prototype.hasOwnProperty.call(json, name)) { + throw new TypeError( + `missing field "${name}" on search: ${JSON.stringify(json)}`); + } + if (typeof json[name] !== 'string') { + throw new TypeError( + `invalid type of filed "${name}" on search: ${JSON.stringify(json)}`); + } + return json[name]; + } + + private static getObjectField(json: any, name: string): Object { + if (!Object.prototype.hasOwnProperty.call(json, name)) { + throw new TypeError( + `missing field "${name}" on search: ${JSON.stringify(json)}`); + } + if (typeof json[name] !== 'object' || json[name] === null) { + throw new TypeError( + `invalid type of filed "${name}" on search: ${JSON.stringify(json)}`); + } + return json[name]; + } +} diff --git a/src/shared/urls.ts b/src/shared/urls.ts index bbdb1ea..64ea4f2 100644 --- a/src/shared/urls.ts +++ b/src/shared/urls.ts @@ -1,4 +1,4 @@ -import { Search } from './Settings'; +import Search from './settings/Search'; const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 @@ -19,7 +19,7 @@ const searchUrl = (keywords: string, search: Search): string => { if (keywords.includes('.') && !keywords.includes(' ')) { return 'http://' + keywords; } - let template = search.engines[search.default]; + let template = search.engines[search.defaultEngine]; let query = keywords; let first = trimStart(keywords).split(' ')[0]; diff --git a/test/content/repositories/SettingRepository.test.ts b/test/content/repositories/SettingRepository.test.ts index 457ca4c..363fcec 100644 --- a/test/content/repositories/SettingRepository.test.ts +++ b/test/content/repositories/SettingRepository.test.ts @@ -1,6 +1,7 @@ import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository'; import { expect } from 'chai'; import Keymaps from '../../../src/shared/settings/Keymaps'; +import Search from '../../../src/shared/settings/Search'; describe('SettingRepositoryImpl', () => { it('updates and gets current value', () => { @@ -8,12 +9,12 @@ describe('SettingRepositoryImpl', () => { let settings = { keymaps: Keymaps.fromJSON({}), - search: { + search: Search.fromJSON({ default: 'google', engines: { google: 'https://google.com/?q={}', } - }, + }), properties: { hintchars: 'abcd1234', smoothscroll: false, diff --git a/test/shared/SettingData.test.ts b/test/shared/SettingData.test.ts index 9567f76..f8995d9 100644 --- a/test/shared/SettingData.test.ts +++ b/test/shared/SettingData.test.ts @@ -4,6 +4,7 @@ import SettingData, { import Settings from '../../src/shared/Settings'; import { expect } from 'chai'; import Keymaps from '../../src/shared/settings/Keymaps'; +import Search from '../../src/shared/settings/Search'; describe('shared/SettingData', () => { describe('FormKeymaps', () => { @@ -60,7 +61,7 @@ describe('shared/SettingData', () => { let settings = JSONTextSettings.fromText(o).toSettings(); expect({ keymaps: settings.keymaps.toJSON(), - search: settings.search, + search: settings.search.toJSON(), properties: settings.properties, blacklist: settings.blacklist, }).to.deep.equal(JSON.parse(o)); @@ -71,12 +72,12 @@ describe('shared/SettingData', () => { it('create from a Settings and create a JSON string', () => { let o = { keymaps: Keymaps.fromJSON({}), - search: { + search: Search.fromJSON({ default: "google", engines: { google: "https://google.com/search?q={}", }, - }, + }), properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, @@ -88,7 +89,7 @@ describe('shared/SettingData', () => { let json = JSONTextSettings.fromSettings(o).toJSONText(); expect(JSON.parse(json)).to.deep.equal({ keymaps: o.keymaps.toJSON(), - search: o.search, + search: o.search.toJSON(), properties: o.properties, blacklist: o.blacklist, }); @@ -121,7 +122,7 @@ describe('shared/SettingData', () => { let settings = FormSettings.valueOf(data).toSettings(); expect({ keymaps: settings.keymaps.toJSON(), - search: settings.search, + search: settings.search.toJSON(), properties: settings.properties, blacklist: settings.blacklist, }).to.deep.equal({ @@ -152,12 +153,12 @@ describe('shared/SettingData', () => { 'j': { type: 'scroll.vertically', count: 1 }, '0': { type: 'scroll.home' }, }), - search: { + search: Search.fromJSON({ default: "google", engines: { "google": "https://google.com/search?q={}" } - }, + }), properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, @@ -278,7 +279,7 @@ describe('shared/SettingData', () => { }; let settings = SettingData.valueOf(data).toSettings(); - expect(settings.search.default).to.equal('google'); + expect(settings.search.defaultEngine).to.equal('google'); }); it('parse object from form source', () => { @@ -302,7 +303,7 @@ describe('shared/SettingData', () => { }; let settings = SettingData.valueOf(data).toSettings(); - expect(settings.search.default).to.equal('yahoo'); + expect(settings.search.defaultEngine).to.equal('yahoo'); }); }); }); diff --git a/test/shared/Settings.test.ts b/test/shared/Settings.test.ts index 9faf9d1..ed791a1 100644 --- a/test/shared/Settings.test.ts +++ b/test/shared/Settings.test.ts @@ -1,67 +1,7 @@ import * as settings from '../../src/shared/Settings'; -import {expect} from 'chai'; +import { expect } from 'chai'; describe('Settings', () => { - describe('#searchValueOf', () => { - it('returns search settings by valid settings', () => { - let search = settings.searchValueOf({ - default: "google", - engines: { - "google": "https://google.com/search?q={}", - "yahoo": "https://search.yahoo.com/search?p={}", - } - }); - - expect(search).to.deep.equal({ - default: "google", - engines: { - "google": "https://google.com/search?q={}", - "yahoo": "https://search.yahoo.com/search?p={}", - } - }); - }); - - it('throws a TypeError by invalid settings', () => { - expect(() => settings.searchValueOf(null)).to.throw(TypeError); - expect(() => settings.searchValueOf({})).to.throw(TypeError); - expect(() => settings.searchValueOf([])).to.throw(TypeError); - expect(() => settings.searchValueOf({ - default: 123, - engines: {} - })).to.throw(TypeError); - expect(() => settings.searchValueOf({ - default: "google", - engines: { - "google": 123456, - } - })).to.throw(TypeError); - expect(() => settings.searchValueOf({ - default: "wikipedia", - engines: { - "google": "https://google.com/search?q={}", - "yahoo": "https://search.yahoo.com/search?p={}", - } - })).to.throw(TypeError); - expect(() => settings.searchValueOf({ - default: "g o o g l e", - engines: { - "g o o g l e": "https://google.com/search?q={}", - } - })).to.throw(TypeError); - expect(() => settings.searchValueOf({ - default: "google", - engines: { - "google": "https://google.com/search", - } - })).to.throw(TypeError); - expect(() => settings.searchValueOf({ - default: "google", - engines: { - "google": "https://google.com/search?q={}&r={}", - } - })).to.throw(TypeError); - }); - }); describe('#propertiesValueOf', () => { it('returns with default properties by empty settings', () => { @@ -129,7 +69,7 @@ describe('Settings', () => { expect({ keymaps: x.keymaps.toJSON(), - search: x.search, + search: x.search.toJSON(), properties: x.properties, blacklist: x.blacklist, }).to.deep.equal({ @@ -153,7 +93,7 @@ describe('Settings', () => { let value = settings.valueOf({}); expect(value.keymaps.toJSON()).to.not.be.empty; expect(value.properties).to.not.be.empty; - expect(value.search.default).to.be.a('string'); + 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/settings/Search.test.ts b/test/shared/settings/Search.test.ts new file mode 100644 index 0000000..7c9134d --- /dev/null +++ b/test/shared/settings/Search.test.ts @@ -0,0 +1,68 @@ +import Search from '../../../src/shared/settings/Search'; +import { expect } from 'chai'; + +describe('Search', () => { + it('returns search settings by valid settings', () => { + let search = Search.fromJSON({ + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?p={}', + } + }); + + expect(search.defaultEngine).to.equal('google') + expect(search.engines).to.deep.equals({ + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?p={}', + }); + expect(search.toJSON()).to.deep.equal({ + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?p={}', + } + }); + }); + + it('throws a TypeError by invalid settings', () => { + expect(() => Search.fromJSON(null)).to.throw(TypeError); + expect(() => Search.fromJSON({})).to.throw(TypeError); + expect(() => Search.fromJSON([])).to.throw(TypeError); + expect(() => Search.fromJSON({ + default: 123, + engines: {} + })).to.throw(TypeError); + expect(() => Search.fromJSON({ + default: 'google', + engines: { + 'google': 123456, + } + })).to.throw(TypeError); + expect(() => Search.fromJSON({ + default: 'wikipedia', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?p={}', + } + })).to.throw(TypeError); + expect(() => Search.fromJSON({ + default: 'g o o g l e', + engines: { + 'g o o g l e': 'https://google.com/search?q={}', + } + })).to.throw(TypeError); + expect(() => Search.fromJSON({ + default: 'google', + engines: { + 'google': 'https://google.com/search', + } + })).to.throw(TypeError); + expect(() => Search.fromJSON({ + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}&r={}', + } + })).to.throw(TypeError); + }); +}); diff --git a/test/shared/urls.test.ts b/test/shared/urls.test.ts index f2950b6..3a3eea6 100644 --- a/test/shared/urls.test.ts +++ b/test/shared/urls.test.ts @@ -1,14 +1,16 @@ -import * as parsers from 'shared/urls'; +import * as parsers from '../../src/shared/urls'; +import { expect } from 'chai'; +import Search from '../../src/shared/settings/Search'; describe("shared/commands/parsers", () => { describe('#searchUrl', () => { - const config = { + const config = Search.fromJSON({ default: 'google', engines: { google: 'https://google.com/search?q={}', yahoo: 'https://yahoo.com/search?q={}', } - }; + }); it('convertes search url', () => { expect(parsers.searchUrl('google.com', config)) -- cgit v1.2.3 From 574692551a27ea56660bf2061daeaa0d34beaff4 Mon Sep 17 00:00:00 2001 From: Shin'ya UEOKA Date: Sat, 5 Oct 2019 02:06:02 +0000 Subject: Make Properties class --- src/background/repositories/SettingRepository.ts | 4 +- src/background/usecases/CompletionsUseCase.ts | 4 +- src/background/usecases/parsers.ts | 4 +- src/settings/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 (limited to 'test/shared/Settings.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" + }); + }); + }); +}); + -- cgit v1.2.3 From b86b4680b6c2a3f0cceefaaf7c2e35417ec555df Mon Sep 17 00:00:00 2001 From: Shin'ya UEOKA Date: Sat, 5 Oct 2019 06:39:20 +0000 Subject: Make Blacklist class --- src/content/controllers/SettingController.ts | 6 +-- src/settings/components/index.tsx | 4 +- src/shared/SettingData.ts | 13 ++--- src/shared/Settings.ts | 21 ++------ src/shared/blacklists.ts | 13 ----- src/shared/settings/Blacklist.ts | 39 ++++++++++++++ src/shared/utils/re.ts | 6 --- test/shared/SettingData.test.ts | 11 ++-- test/shared/Settings.test.ts | 30 +---------- test/shared/blacklists.test.ts | 49 ------------------ test/shared/settings/Blacklist.test.ts | 77 ++++++++++++++++++++++++++++ test/shared/utils/re.test.ts | 19 ------- 12 files changed, 139 insertions(+), 149 deletions(-) delete mode 100644 src/shared/blacklists.ts create mode 100644 src/shared/settings/Blacklist.ts delete mode 100644 src/shared/utils/re.ts delete mode 100644 test/shared/blacklists.test.ts create mode 100644 test/shared/settings/Blacklist.test.ts delete mode 100644 test/shared/utils/re.test.ts (limited to 'test/shared/Settings.test.ts') diff --git a/src/content/controllers/SettingController.ts b/src/content/controllers/SettingController.ts index 7fb045b..06273a0 100644 --- a/src/content/controllers/SettingController.ts +++ b/src/content/controllers/SettingController.ts @@ -1,8 +1,6 @@ import { injectable } from 'tsyringe'; import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; import SettingUseCase from '../usecases/SettingUseCase'; -import * as blacklists from '../../shared/blacklists'; - import * as messages from '../../shared/messages'; @injectable() @@ -17,9 +15,7 @@ export default class SettingController { async initSettings(): Promise { try { let current = await this.settingUseCase.reload(); - let disabled = blacklists.includes( - current.blacklist, window.location.href, - ); + let disabled = current.blacklist.includes(window.location.href); if (disabled) { this.addonEnabledUseCase.disable(); } else { diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index e86d765..bd99d52 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -11,8 +11,8 @@ import SettingData, { FormKeymaps, FormSearch, FormSettings, JSONTextSettings, } from '../../shared/SettingData'; import { State as AppState } from '../reducers/setting'; -import * as settings from '../../shared/Settings'; import Properties from '../../shared/settings/Properties'; +import Blacklist from '../../shared/settings/Blacklist'; const DO_YOU_WANT_TO_CONTINUE = 'Some settings in JSON can be lost when migrating. ' + @@ -143,7 +143,7 @@ class SettingsComponent extends React.Component { let data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithBlacklist( - settings.blacklistValueOf(value)), + Blacklist.fromJSON(value)), }); this.props.dispatch(settingActions.set(data)); } diff --git a/src/shared/SettingData.ts b/src/shared/SettingData.ts index aa4e382..8ef8385 100644 --- a/src/shared/SettingData.ts +++ b/src/shared/SettingData.ts @@ -3,6 +3,7 @@ import Settings, * as settings from './Settings'; import Keymaps from './settings/Keymaps'; import Search from './settings/Search'; import Properties from './settings/Properties'; +import Blacklist from './settings/Blacklist'; export class FormKeymaps { private data: {[op: string]: string}; @@ -146,13 +147,13 @@ export class FormSettings { private properties: Properties; - private blacklist: string[]; + private blacklist: Blacklist; constructor( keymaps: FormKeymaps, search: FormSearch, properties: Properties, - blacklist: string[], + blacklist: Blacklist, ) { this.keymaps = keymaps; this.search = search; @@ -187,7 +188,7 @@ export class FormSettings { ); } - buildWithBlacklist(blacklist: string[]): FormSettings { + buildWithBlacklist(blacklist: Blacklist): FormSettings { return new FormSettings( this.keymaps, this.search, @@ -201,7 +202,7 @@ export class FormSettings { keymaps: this.keymaps.toKeymaps().toJSON(), search: this.search.toSearchSettings().toJSON(), properties: this.properties.toJSON(), - blacklist: this.blacklist, + blacklist: this.blacklist.toJSON(), }); } @@ -215,7 +216,7 @@ export class FormSettings { keymaps: this.keymaps.toJSON(), search: this.search.toJSON(), properties: this.properties.toJSON(), - blacklist: this.blacklist, + blacklist: this.blacklist.toJSON(), }; } @@ -229,7 +230,7 @@ export class FormSettings { FormKeymaps.valueOf(o.keymaps), FormSearch.valueOf(o.search), Properties.fromJSON(o.properties), - settings.blacklistValueOf(o.blacklist), + Blacklist.fromJSON(o.blacklist), ); } diff --git a/src/shared/Settings.ts b/src/shared/Settings.ts index 6250aae..2767820 100644 --- a/src/shared/Settings.ts +++ b/src/shared/Settings.ts @@ -1,26 +1,15 @@ import Keymaps from './settings/Keymaps'; import Search from './settings/Search'; import Properties from './settings/Properties'; +import Blacklist from './settings/Blacklist'; export default interface Settings { keymaps: Keymaps; search: Search; properties: Properties; - blacklist: string[]; + blacklist: Blacklist; } -export const blacklistValueOf = (o: any): string[] => { - if (!Array.isArray(o)) { - throw new TypeError(`"blacklist" is not an array of string`); - } - for (let x of o) { - if (typeof x !== 'string') { - throw new TypeError(`"blacklist" is not an array of string`); - } - } - return o as string[]; -}; - export const valueOf = (o: any): Settings => { let settings = { ...DefaultSetting }; for (let key of Object.keys(o)) { @@ -35,7 +24,7 @@ export const valueOf = (o: any): Settings => { settings.properties = Properties.fromJSON(o.properties); break; case 'blacklist': - settings.blacklist = blacklistValueOf(o.blacklist); + settings.blacklist = Blacklist.fromJSON(o.blacklist); break; default: throw new TypeError('unknown setting: ' + key); @@ -49,7 +38,7 @@ export const toJSON = (settings: Settings): any => { keymaps: settings.keymaps.toJSON(), search: settings.search.toJSON(), properties: settings.properties.toJSON(), - blacklist: settings.blacklist, + blacklist: settings.blacklist.toJSON(), }; }; @@ -134,5 +123,5 @@ export const DefaultSetting: Settings = { smoothscroll: false, complete: 'sbh' }), - blacklist: [] + blacklist: Blacklist.fromJSON([]), }; diff --git a/src/shared/blacklists.ts b/src/shared/blacklists.ts deleted file mode 100644 index 61ee4de..0000000 --- a/src/shared/blacklists.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as re from './utils/re'; - -const includes = (blacklist: string[], url: string): boolean => { - let u = new URL(url); - return blacklist.some((item) => { - if (!item.includes('/')) { - return re.fromWildcard(item).test(u.host); - } - return re.fromWildcard(item).test(u.host + u.pathname); - }); -}; - -export { includes }; diff --git a/src/shared/settings/Blacklist.ts b/src/shared/settings/Blacklist.ts new file mode 100644 index 0000000..a95b606 --- /dev/null +++ b/src/shared/settings/Blacklist.ts @@ -0,0 +1,39 @@ +export type BlacklistJSON = string[]; + +const fromWildcard = (pattern: string): RegExp => { + let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$'; + return new RegExp(regexStr); +}; + +export default class Blacklist { + constructor( + private blacklist: string[], + ) { + } + + static fromJSON(json: any): Blacklist { + if (!Array.isArray(json)) { + throw new TypeError(`"blacklist" is not an array of string`); + } + for (let x of json) { + if (typeof x !== 'string') { + throw new TypeError(`"blacklist" is not an array of string`); + } + } + return new Blacklist(json); + } + + toJSON(): BlacklistJSON { + return this.blacklist; + } + + includes(url: string): boolean { + let u = new URL(url); + return this.blacklist.some((item) => { + if (!item.includes('/')) { + return fromWildcard(item).test(u.host); + } + return fromWildcard(item).test(u.host + u.pathname); + }); + } +} diff --git a/src/shared/utils/re.ts b/src/shared/utils/re.ts deleted file mode 100644 index 34f4fa6..0000000 --- a/src/shared/utils/re.ts +++ /dev/null @@ -1,6 +0,0 @@ -const fromWildcard = (pattern: string): RegExp => { - let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$'; - return new RegExp(regexStr); -}; - -export { fromWildcard }; diff --git a/test/shared/SettingData.test.ts b/test/shared/SettingData.test.ts index b5bf70e..4391e73 100644 --- a/test/shared/SettingData.test.ts +++ b/test/shared/SettingData.test.ts @@ -6,6 +6,7 @@ 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'; +import Blacklist from '../../src/shared/settings/Blacklist' describe('shared/SettingData', () => { describe('FormKeymaps', () => { @@ -64,7 +65,7 @@ describe('shared/SettingData', () => { keymaps: settings.keymaps.toJSON(), search: settings.search.toJSON(), properties: settings.properties.toJSON(), - blacklist: settings.blacklist, + blacklist: settings.blacklist.toJSON(), }).to.deep.equal(JSON.parse(o)); }); }); @@ -84,7 +85,7 @@ describe('shared/SettingData', () => { smoothscroll: false, complete: "sbh" }), - blacklist: [], + blacklist: Blacklist.fromJSON([]), }; let json = JSONTextSettings.fromSettings(o).toJSONText(); @@ -92,7 +93,7 @@ describe('shared/SettingData', () => { keymaps: o.keymaps.toJSON(), search: o.search.toJSON(), properties: o.properties.toJSON(), - blacklist: o.blacklist, + blacklist: o.blacklist.toJSON(), }); }); }); @@ -125,7 +126,7 @@ describe('shared/SettingData', () => { keymaps: settings.keymaps.toJSON(), search: settings.search.toJSON(), properties: settings.properties.toJSON(), - blacklist: settings.blacklist, + blacklist: settings.blacklist.toJSON(), }).to.deep.equal({ keymaps: { 'j': { type: 'scroll.vertically', count: 1 }, @@ -165,7 +166,7 @@ describe('shared/SettingData', () => { smoothscroll: false, complete: "sbh" }), - blacklist: [] + blacklist: Blacklist.fromJSON([]), }; let json = FormSettings.fromSettings(data).toJSON(); diff --git a/test/shared/Settings.test.ts b/test/shared/Settings.test.ts index 6360bab..9688798 100644 --- a/test/shared/Settings.test.ts +++ b/test/shared/Settings.test.ts @@ -2,32 +2,6 @@ import * as settings from '../../src/shared/Settings'; import {expect} from 'chai'; describe('Settings', () => { - - describe('#blacklistValueOf', () => { - it('returns empty array by empty settings', () => { - let blacklist = settings.blacklistValueOf([]); - expect(blacklist).to.be.empty; - }); - - it('returns blacklist by valid settings', () => { - let blacklist = settings.blacklistValueOf([ - "github.com", - "circleci.com", - ]); - - expect(blacklist).to.deep.equal([ - "github.com", - "circleci.com", - ]); - }); - - it('throws a TypeError by invalid settings', () => { - expect(() => settings.blacklistValueOf(null)).to.throw(TypeError); - expect(() => settings.blacklistValueOf({})).to.throw(TypeError); - expect(() => settings.blacklistValueOf([1,2,3])).to.throw(TypeError); - }); - }); - describe('#valueOf', () => { it('returns settings by valid settings', () => { let x = settings.valueOf({ @@ -46,7 +20,7 @@ describe('Settings', () => { keymaps: x.keymaps.toJSON(), search: x.search.toJSON(), properties: x.properties.toJSON(), - blacklist: x.blacklist, + blacklist: x.blacklist.toJSON(), }).to.deep.equal({ keymaps: {}, search: { @@ -70,7 +44,7 @@ describe('Settings', () => { 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; + expect(value.blacklist.toJSON()).to.be.empty; }); it('throws a TypeError with an unknown field', () => { diff --git a/test/shared/blacklists.test.ts b/test/shared/blacklists.test.ts deleted file mode 100644 index 289ea0f..0000000 --- a/test/shared/blacklists.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { includes } from 'shared/blacklists'; - -describe("shared/blacklist", () => { - it('matches by *', () => { - let blacklist = ['*']; - - expect(includes(blacklist, 'https://github.com/abc')).to.be.true; - }) - - it('matches by hostname', () => { - let blacklist = ['github.com']; - - expect(includes(blacklist, 'https://github.com')).to.be.true; - expect(includes(blacklist, 'https://gist.github.com')).to.be.false; - expect(includes(blacklist, 'https://github.com/ueokande')).to.be.true; - expect(includes(blacklist, 'https://github.org')).to.be.false; - expect(includes(blacklist, 'https://google.com/search?q=github.org')).to.be.false; - }) - - it('matches by hostname with wildcard', () => { - let blacklist = ['*.github.com']; - - expect(includes(blacklist, 'https://github.com')).to.be.false; - expect(includes(blacklist, 'https://gist.github.com')).to.be.true; - }) - - it('matches by path', () => { - let blacklist = ['github.com/abc']; - - expect(includes(blacklist, 'https://github.com/abc')).to.be.true; - expect(includes(blacklist, 'https://github.com/abcdef')).to.be.false; - expect(includes(blacklist, 'https://gist.github.com/abc')).to.be.false; - }) - - it('matches by path with wildcard', () => { - let blacklist = ['github.com/abc*']; - - expect(includes(blacklist, 'https://github.com/abc')).to.be.true; - expect(includes(blacklist, 'https://github.com/abcdef')).to.be.true; - expect(includes(blacklist, 'https://gist.github.com/abc')).to.be.false; - }) - - it('matches address and port', () => { - let blacklist = ['127.0.0.1:8888']; - - expect(includes(blacklist, 'http://127.0.0.1:8888/')).to.be.true; - expect(includes(blacklist, 'http://127.0.0.1:8888/hello')).to.be.true; - }) -}); diff --git a/test/shared/settings/Blacklist.test.ts b/test/shared/settings/Blacklist.test.ts new file mode 100644 index 0000000..fbacf5d --- /dev/null +++ b/test/shared/settings/Blacklist.test.ts @@ -0,0 +1,77 @@ +import Blacklist from '../../../src/shared/settings/Blacklist'; +import { expect } from 'chai'; + +describe('Blacklist', () => { + describe('fromJSON', () => { + it('returns empty array by empty settings', () => { + let blacklist = Blacklist.fromJSON([]); + expect(blacklist.toJSON()).to.be.empty; + }); + + it('returns blacklist by valid settings', () => { + let blacklist = Blacklist.fromJSON([ + 'github.com', + 'circleci.com', + ]); + + expect(blacklist.toJSON()).to.deep.equal([ + 'github.com', + 'circleci.com', + ]); + }); + + it('throws a TypeError by invalid settings', () => { + expect(() => Blacklist.fromJSON(null)).to.throw(TypeError); + expect(() => Blacklist.fromJSON({})).to.throw(TypeError); + expect(() => Blacklist.fromJSON([1,2,3])).to.throw(TypeError); + }); + }); + + describe('#includes', () => { + it('matches by *', () => { + let blacklist = new Blacklist(['*']); + + expect(blacklist.includes('https://github.com/abc')).to.be.true; + }); + + it('matches by hostname', () => { + let blacklist = new Blacklist(['github.com']); + + expect(blacklist.includes('https://github.com')).to.be.true; + expect(blacklist.includes('https://gist.github.com')).to.be.false; + expect(blacklist.includes('https://github.com/ueokande')).to.be.true; + expect(blacklist.includes('https://github.org')).to.be.false; + expect(blacklist.includes('https://google.com/search?q=github.org')).to.be.false; + }); + + it('matches by hostname with wildcard', () => { + let blacklist = new Blacklist(['*.github.com']); + + expect(blacklist.includes('https://github.com')).to.be.false; + expect(blacklist.includes('https://gist.github.com')).to.be.true; + }) + + it('matches by path', () => { + let blacklist = new Blacklist(['github.com/abc']); + + expect(blacklist.includes('https://github.com/abc')).to.be.true; + expect(blacklist.includes('https://github.com/abcdef')).to.be.false; + expect(blacklist.includes('https://gist.github.com/abc')).to.be.false; + }) + + it('matches by path with wildcard', () => { + let blacklist = new Blacklist(['github.com/abc*']); + + expect(blacklist.includes('https://github.com/abc')).to.be.true; + expect(blacklist.includes('https://github.com/abcdef')).to.be.true; + expect(blacklist.includes('https://gist.github.com/abc')).to.be.false; + }) + + it('matches address and port', () => { + let blacklist = new Blacklist(['127.0.0.1:8888']); + + expect(blacklist.includes('http://127.0.0.1:8888/')).to.be.true; + expect(blacklist.includes('http://127.0.0.1:8888/hello')).to.be.true; + }) + }) +}); diff --git a/test/shared/utils/re.test.ts b/test/shared/utils/re.test.ts deleted file mode 100644 index d12ceb7..0000000 --- a/test/shared/utils/re.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as re from 'shared/utils/re'; - -describe("re util", () => { - it('matches by pattern', () => { - let regex = re.fromWildcard('*.example.com/*'); - expect('foo.example.com/bar').to.match(regex); - expect('foo.example.com').not.to.match(regex); - expect('example.com/bar').not.to.match(regex); - - regex = re.fromWildcard('example.com/*') - expect('example.com/foo').to.match(regex); - expect('example.com/').to.match(regex); - - regex = re.fromWildcard('example.com/*bar') - expect('example.com/foobar').to.match(regex); - expect('example.com/bar').to.match(regex); - expect('example.com/foobarfoo').not.to.match(regex); - }) -}); -- cgit v1.2.3 From 0dec6c641fc11348f89a12680a087ccda1181f66 Mon Sep 17 00:00:00 2001 From: Shin'ya UEOKA Date: Sat, 5 Oct 2019 07:19:48 +0000 Subject: Make Settings class --- src/background/controllers/SettingController.ts | 2 +- .../infrastructures/ContentMessageListener.ts | 3 +- src/background/repositories/SettingRepository.ts | 7 +- src/background/usecases/SettingUseCase.ts | 2 +- src/content/client/SettingClient.ts | 4 +- src/content/repositories/SettingRepository.ts | 2 +- src/content/usecases/SettingUseCase.ts | 2 +- src/shared/SettingData.ts | 6 +- src/shared/Settings.ts | 127 ----------------- src/shared/settings/Settings.ts | 154 +++++++++++++++++++++ .../content/repositories/SettingRepository.test.ts | 13 +- test/content/usecases/SettingUseCaase.test.ts | 2 +- test/shared/SettingData.test.ts | 39 +++--- test/shared/Settings.test.ts | 54 -------- test/shared/settings/Settings.test.ts | 54 ++++++++ 15 files changed, 246 insertions(+), 225 deletions(-) delete mode 100644 src/shared/Settings.ts create mode 100644 src/shared/settings/Settings.ts delete mode 100644 test/shared/Settings.test.ts create mode 100644 test/shared/settings/Settings.test.ts (limited to 'test/shared/Settings.test.ts') diff --git a/src/background/controllers/SettingController.ts b/src/background/controllers/SettingController.ts index 34951ff..8d05852 100644 --- a/src/background/controllers/SettingController.ts +++ b/src/background/controllers/SettingController.ts @@ -1,7 +1,7 @@ import { injectable } from 'tsyringe'; import SettingUseCase from '../usecases/SettingUseCase'; import ContentMessageClient from '../infrastructures/ContentMessageClient'; -import Settings from '../../shared/Settings'; +import Settings from '../../shared/settings/Settings'; @injectable() export default class SettingController { diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index f348a74..f80d686 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -8,7 +8,6 @@ import AddonEnabledController from '../controllers/AddonEnabledController'; import LinkController from '../controllers/LinkController'; import OperationController from '../controllers/OperationController'; import MarkController from '../controllers/MarkController'; -import { toJSON } from '../../shared/Settings'; @injectable() export default class ContentMessageListener { @@ -103,7 +102,7 @@ export default class ContentMessageListener { } async onSettingsQuery(): Promise { - return toJSON(await this.settingController.getSetting()); + return (await this.settingController.getSetting()).toJSON(); } onFindGetKeyword(): Promise { diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts index a11b65f..e775a32 100644 --- a/src/background/repositories/SettingRepository.ts +++ b/src/background/repositories/SettingRepository.ts @@ -1,6 +1,6 @@ import { injectable } from 'tsyringe'; import MemoryStorage from '../infrastructures/MemoryStorage'; -import Settings, { valueOf, toJSON } from '../../shared/Settings'; +import Settings from '../../shared/settings/Settings'; import Properties from '../../shared/settings/Properties'; const CACHED_SETTING_KEY = 'setting'; @@ -15,12 +15,11 @@ export default class SettingRepository { get(): Promise { let data = this.cache.get(CACHED_SETTING_KEY); - return Promise.resolve(valueOf(data)); + return Promise.resolve(Settings.fromJSON(data)); } update(value: Settings): void { - let data = toJSON(value); - return this.cache.set(CACHED_SETTING_KEY, data); + return this.cache.set(CACHED_SETTING_KEY, value.toJSON()); } async setProperty( diff --git a/src/background/usecases/SettingUseCase.ts b/src/background/usecases/SettingUseCase.ts index d73521f..d78d440 100644 --- a/src/background/usecases/SettingUseCase.ts +++ b/src/background/usecases/SettingUseCase.ts @@ -3,7 +3,7 @@ import PersistentSettingRepository from '../repositories/PersistentSettingRepository'; import SettingRepository from '../repositories/SettingRepository'; import { DefaultSettingData } from '../../shared/SettingData'; -import Settings from '../../shared/Settings'; +import Settings from '../../shared/settings/Settings'; import NotifyPresenter from '../presenters/NotifyPresenter'; @injectable() diff --git a/src/content/client/SettingClient.ts b/src/content/client/SettingClient.ts index a7cd1ee..fc62720 100644 --- a/src/content/client/SettingClient.ts +++ b/src/content/client/SettingClient.ts @@ -1,4 +1,4 @@ -import Settings, { valueOf } from '../../shared/Settings'; +import Settings from '../../shared/settings/Settings'; import * as messages from '../../shared/messages'; export default interface SettingClient { @@ -10,6 +10,6 @@ export class SettingClientImpl { let settings = await browser.runtime.sendMessage({ type: messages.SETTINGS_QUERY, }); - return valueOf(settings); + return Settings.fromJSON(settings); } } diff --git a/src/content/repositories/SettingRepository.ts b/src/content/repositories/SettingRepository.ts index d718794..4ba26e0 100644 --- a/src/content/repositories/SettingRepository.ts +++ b/src/content/repositories/SettingRepository.ts @@ -1,4 +1,4 @@ -import Settings, { DefaultSetting } from '../../shared/Settings'; +import Settings, { DefaultSetting } from '../../shared/settings/Settings'; let current: Settings = DefaultSetting; diff --git a/src/content/usecases/SettingUseCase.ts b/src/content/usecases/SettingUseCase.ts index d5f66c6..4608039 100644 --- a/src/content/usecases/SettingUseCase.ts +++ b/src/content/usecases/SettingUseCase.ts @@ -1,7 +1,7 @@ import { injectable, inject } from 'tsyringe'; import SettingRepository from '../repositories/SettingRepository'; import SettingClient from '../client/SettingClient'; -import Settings from '../../shared/Settings'; +import Settings from '../../shared/settings/Settings'; @injectable() export default class SettingUseCase { diff --git a/src/shared/SettingData.ts b/src/shared/SettingData.ts index 8ef8385..2dedfef 100644 --- a/src/shared/SettingData.ts +++ b/src/shared/SettingData.ts @@ -1,5 +1,5 @@ import * as operations from './operations'; -import Settings, * as settings from './Settings'; +import Settings from './settings/Settings'; import Keymaps from './settings/Keymaps'; import Search from './settings/Search'; import Properties from './settings/Properties'; @@ -118,7 +118,7 @@ export class JSONTextSettings { } toSettings(): Settings { - return settings.valueOf(JSON.parse(this.json)); + return Settings.fromJSON(JSON.parse(this.json)); } toJSONText(): string { @@ -198,7 +198,7 @@ export class FormSettings { } toSettings(): Settings { - return settings.valueOf({ + return Settings.fromJSON({ keymaps: this.keymaps.toKeymaps().toJSON(), search: this.search.toSearchSettings().toJSON(), properties: this.properties.toJSON(), diff --git a/src/shared/Settings.ts b/src/shared/Settings.ts deleted file mode 100644 index 2767820..0000000 --- a/src/shared/Settings.ts +++ /dev/null @@ -1,127 +0,0 @@ -import Keymaps from './settings/Keymaps'; -import Search from './settings/Search'; -import Properties from './settings/Properties'; -import Blacklist from './settings/Blacklist'; - -export default interface Settings { - keymaps: Keymaps; - search: Search; - properties: Properties; - blacklist: Blacklist; -} - -export const valueOf = (o: any): Settings => { - let settings = { ...DefaultSetting }; - for (let key of Object.keys(o)) { - switch (key) { - case 'keymaps': - settings.keymaps = Keymaps.fromJSON(o.keymaps); - break; - case 'search': - settings.search = Search.fromJSON(o.search); - break; - case 'properties': - settings.properties = Properties.fromJSON(o.properties); - break; - case 'blacklist': - settings.blacklist = Blacklist.fromJSON(o.blacklist); - break; - default: - throw new TypeError('unknown setting: ' + key); - } - } - return settings; -}; - -export const toJSON = (settings: Settings): any => { - return { - keymaps: settings.keymaps.toJSON(), - search: settings.search.toJSON(), - properties: settings.properties.toJSON(), - blacklist: settings.blacklist.toJSON(), - }; -}; - -export const DefaultSetting: Settings = { - keymaps: Keymaps.fromJSON({ - '0': { 'type': 'scroll.home' }, - ':': { 'type': 'command.show' }, - 'o': { 'type': 'command.show.open', 'alter': false }, - 'O': { 'type': 'command.show.open', 'alter': true }, - 't': { 'type': 'command.show.tabopen', 'alter': false }, - 'T': { 'type': 'command.show.tabopen', 'alter': true }, - 'w': { 'type': 'command.show.winopen', 'alter': false }, - 'W': { 'type': 'command.show.winopen', 'alter': true }, - 'b': { 'type': 'command.show.buffer' }, - 'a': { 'type': 'command.show.addbookmark', 'alter': true }, - 'k': { 'type': 'scroll.vertically', 'count': -1 }, - 'j': { 'type': 'scroll.vertically', 'count': 1 }, - 'h': { 'type': 'scroll.horizonally', 'count': -1 }, - 'l': { 'type': 'scroll.horizonally', 'count': 1 }, - '': { 'type': 'scroll.pages', 'count': -0.5 }, - '': { 'type': 'scroll.pages', 'count': 0.5 }, - '': { 'type': 'scroll.pages', 'count': -1 }, - '': { 'type': 'scroll.pages', 'count': 1 }, - 'gg': { 'type': 'scroll.top' }, - 'G': { 'type': 'scroll.bottom' }, - '$': { 'type': 'scroll.end' }, - 'd': { 'type': 'tabs.close' }, - 'D': { 'type': 'tabs.close', 'select': 'left' }, - 'x$': { 'type': 'tabs.close.right' }, - '!d': { 'type': 'tabs.close.force' }, - 'u': { 'type': 'tabs.reopen' }, - 'K': { 'type': 'tabs.prev' }, - 'J': { 'type': 'tabs.next' }, - 'gT': { 'type': 'tabs.prev' }, - 'gt': { 'type': 'tabs.next' }, - 'g0': { 'type': 'tabs.first' }, - 'g$': { 'type': 'tabs.last' }, - '': { 'type': 'tabs.prevsel' }, - 'r': { 'type': 'tabs.reload', 'cache': false }, - 'R': { 'type': 'tabs.reload', 'cache': true }, - 'zp': { 'type': 'tabs.pin.toggle' }, - 'zd': { 'type': 'tabs.duplicate' }, - 'zi': { 'type': 'zoom.in' }, - 'zo': { 'type': 'zoom.out' }, - 'zz': { 'type': 'zoom.neutral' }, - 'f': { 'type': 'follow.start', 'newTab': false, 'background': false }, - 'F': { 'type': 'follow.start', 'newTab': true, 'background': false }, - 'm': { 'type': 'mark.set.prefix' }, - '\'': { 'type': 'mark.jump.prefix' }, - 'H': { 'type': 'navigate.history.prev' }, - 'L': { 'type': 'navigate.history.next' }, - '[[': { 'type': 'navigate.link.prev' }, - ']]': { 'type': 'navigate.link.next' }, - 'gu': { 'type': 'navigate.parent' }, - 'gU': { 'type': 'navigate.root' }, - 'gi': { 'type': 'focus.input' }, - 'gf': { 'type': 'page.source' }, - 'gh': { 'type': 'page.home', 'newTab': false }, - 'gH': { 'type': 'page.home', 'newTab': true }, - 'y': { 'type': 'urls.yank' }, - 'p': { 'type': 'urls.paste', 'newTab': false }, - 'P': { 'type': 'urls.paste', 'newTab': true }, - '/': { 'type': 'find.start' }, - 'n': { 'type': 'find.next' }, - 'N': { 'type': 'find.prev' }, - '.': { 'type': 'repeat.last' }, - '': { 'type': 'addon.toggle.enabled' } - }), - search: Search.fromJSON({ - default: 'google', - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?p={}', - 'bing': 'https://www.bing.com/search?q={}', - 'duckduckgo': 'https://duckduckgo.com/?q={}', - 'twitter': 'https://twitter.com/search?q={}', - 'wikipedia': 'https://en.wikipedia.org/w/index.php?search={}' - } - }), - properties: Properties.fromJSON({ - hintchars: 'abcdefghijklmnopqrstuvwxyz', - smoothscroll: false, - complete: 'sbh' - }), - blacklist: Blacklist.fromJSON([]), -}; diff --git a/src/shared/settings/Settings.ts b/src/shared/settings/Settings.ts new file mode 100644 index 0000000..116c7d7 --- /dev/null +++ b/src/shared/settings/Settings.ts @@ -0,0 +1,154 @@ +import Keymaps, { KeymapsJSON } from './Keymaps'; +import Search, { SearchJSON } from './Search'; +import Properties, { PropertiesJSON } from './Properties'; +import Blacklist, { BlacklistJSON } from './Blacklist'; + +export type SettingsJSON = { + keymaps: KeymapsJSON, + search: SearchJSON, + properties: PropertiesJSON, + blacklist: BlacklistJSON, +}; + +export default class Settings { + public keymaps: Keymaps; + + public search: Search; + + public properties: Properties; + + public blacklist: Blacklist; + + constructor({ + keymaps, + search, + properties, + blacklist, + }: { + keymaps: Keymaps; + search: Search; + properties: Properties; + blacklist: Blacklist; + }) { + this.keymaps = keymaps; + this.search = search; + this.properties = properties; + this.blacklist = blacklist; + } + + static fromJSON(json: any): Settings { + let settings = { ...DefaultSetting }; + for (let key of Object.keys(json)) { + switch (key) { + case 'keymaps': + settings.keymaps = Keymaps.fromJSON(json.keymaps); + break; + case 'search': + settings.search = Search.fromJSON(json.search); + break; + case 'properties': + settings.properties = Properties.fromJSON(json.properties); + break; + case 'blacklist': + settings.blacklist = Blacklist.fromJSON(json.blacklist); + break; + default: + throw new TypeError('unknown setting: ' + key); + } + } + return new Settings(settings); + } + + toJSON(): SettingsJSON { + return { + keymaps: this.keymaps.toJSON(), + search: this.search.toJSON(), + properties: this.properties.toJSON(), + blacklist: this.blacklist.toJSON(), + }; + } +} + +export const DefaultSetting: Settings = Settings.fromJSON({ + keymaps: { + '0': { 'type': 'scroll.home' }, + ':': { 'type': 'command.show' }, + 'o': { 'type': 'command.show.open', 'alter': false }, + 'O': { 'type': 'command.show.open', 'alter': true }, + 't': { 'type': 'command.show.tabopen', 'alter': false }, + 'T': { 'type': 'command.show.tabopen', 'alter': true }, + 'w': { 'type': 'command.show.winopen', 'alter': false }, + 'W': { 'type': 'command.show.winopen', 'alter': true }, + 'b': { 'type': 'command.show.buffer' }, + 'a': { 'type': 'command.show.addbookmark', 'alter': true }, + 'k': { 'type': 'scroll.vertically', 'count': -1 }, + 'j': { 'type': 'scroll.vertically', 'count': 1 }, + 'h': { 'type': 'scroll.horizonally', 'count': -1 }, + 'l': { 'type': 'scroll.horizonally', 'count': 1 }, + '': { 'type': 'scroll.pages', 'count': -0.5 }, + '': { 'type': 'scroll.pages', 'count': 0.5 }, + '': { 'type': 'scroll.pages', 'count': -1 }, + '': { 'type': 'scroll.pages', 'count': 1 }, + 'gg': { 'type': 'scroll.top' }, + 'G': { 'type': 'scroll.bottom' }, + '$': { 'type': 'scroll.end' }, + 'd': { 'type': 'tabs.close' }, + 'D': { 'type': 'tabs.close', 'select': 'left' }, + 'x$': { 'type': 'tabs.close.right' }, + '!d': { 'type': 'tabs.close.force' }, + 'u': { 'type': 'tabs.reopen' }, + 'K': { 'type': 'tabs.prev' }, + 'J': { 'type': 'tabs.next' }, + 'gT': { 'type': 'tabs.prev' }, + 'gt': { 'type': 'tabs.next' }, + 'g0': { 'type': 'tabs.first' }, + 'g$': { 'type': 'tabs.last' }, + '': { 'type': 'tabs.prevsel' }, + 'r': { 'type': 'tabs.reload', 'cache': false }, + 'R': { 'type': 'tabs.reload', 'cache': true }, + 'zp': { 'type': 'tabs.pin.toggle' }, + 'zd': { 'type': 'tabs.duplicate' }, + 'zi': { 'type': 'zoom.in' }, + 'zo': { 'type': 'zoom.out' }, + 'zz': { 'type': 'zoom.neutral' }, + 'f': { 'type': 'follow.start', 'newTab': false, 'background': false }, + 'F': { 'type': 'follow.start', 'newTab': true, 'background': false }, + 'm': { 'type': 'mark.set.prefix' }, + '\'': { 'type': 'mark.jump.prefix' }, + 'H': { 'type': 'navigate.history.prev' }, + 'L': { 'type': 'navigate.history.next' }, + '[[': { 'type': 'navigate.link.prev' }, + ']]': { 'type': 'navigate.link.next' }, + 'gu': { 'type': 'navigate.parent' }, + 'gU': { 'type': 'navigate.root' }, + 'gi': { 'type': 'focus.input' }, + 'gf': { 'type': 'page.source' }, + 'gh': { 'type': 'page.home', 'newTab': false }, + 'gH': { 'type': 'page.home', 'newTab': true }, + 'y': { 'type': 'urls.yank' }, + 'p': { 'type': 'urls.paste', 'newTab': false }, + 'P': { 'type': 'urls.paste', 'newTab': true }, + '/': { 'type': 'find.start' }, + 'n': { 'type': 'find.next' }, + 'N': { 'type': 'find.prev' }, + '.': { 'type': 'repeat.last' }, + '': { 'type': 'addon.toggle.enabled' } + }, + search: { + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?p={}', + 'bing': 'https://www.bing.com/search?q={}', + 'duckduckgo': 'https://duckduckgo.com/?q={}', + 'twitter': 'https://twitter.com/search?q={}', + 'wikipedia': 'https://en.wikipedia.org/w/index.php?search={}' + } + }, + properties: { + hintchars: 'abcdefghijklmnopqrstuvwxyz', + smoothscroll: false, + complete: 'sbh' + }, + blacklist: [], +}); diff --git a/test/content/repositories/SettingRepository.test.ts b/test/content/repositories/SettingRepository.test.ts index 363fcec..db4c528 100644 --- a/test/content/repositories/SettingRepository.test.ts +++ b/test/content/repositories/SettingRepository.test.ts @@ -1,27 +1,26 @@ import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository'; import { expect } from 'chai'; -import Keymaps from '../../../src/shared/settings/Keymaps'; -import Search from '../../../src/shared/settings/Search'; +import Settings from '../../../src/shared/settings/Settings'; describe('SettingRepositoryImpl', () => { it('updates and gets current value', () => { let sut = new SettingRepositoryImpl(); - let settings = { - keymaps: Keymaps.fromJSON({}), - search: Search.fromJSON({ + let settings = Settings.fromJSON({ + keymaps: {}, + search:{ default: 'google', engines: { google: 'https://google.com/?q={}', } - }), + }, properties: { hintchars: 'abcd1234', smoothscroll: false, complete: 'sbh', }, blacklist: [], - }; + }); sut.set(settings); diff --git a/test/content/usecases/SettingUseCaase.test.ts b/test/content/usecases/SettingUseCaase.test.ts index e9633f4..136c5af 100644 --- a/test/content/usecases/SettingUseCaase.test.ts +++ b/test/content/usecases/SettingUseCaase.test.ts @@ -1,7 +1,7 @@ import SettingRepository from '../../../src/content/repositories/SettingRepository'; import SettingClient from '../../../src/content/client/SettingClient'; import SettingUseCase from '../../../src/content/usecases/SettingUseCase'; -import Settings, { DefaultSetting } from '../../../src/shared/Settings'; +import Settings, { DefaultSetting } from '../../../src/shared/settings/Settings'; import { expect } from 'chai'; class MockSettingRepository implements SettingRepository { diff --git a/test/shared/SettingData.test.ts b/test/shared/SettingData.test.ts index 4391e73..138d768 100644 --- a/test/shared/SettingData.test.ts +++ b/test/shared/SettingData.test.ts @@ -1,12 +1,9 @@ import SettingData, { FormKeymaps, JSONTextSettings, FormSettings, } from '../../src/shared/SettingData'; -import Settings from '../../src/shared/Settings'; +import Settings from '../../src/shared/settings/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'; -import Blacklist from '../../src/shared/settings/Blacklist' describe('shared/SettingData', () => { describe('FormKeymaps', () => { @@ -72,21 +69,21 @@ describe('shared/SettingData', () => { describe('#fromSettings to #toJSON', () => { it('create from a Settings and create a JSON string', () => { - let o = { - keymaps: Keymaps.fromJSON({}), - search: Search.fromJSON({ + let o = Settings.fromJSON({ + keymaps: {}, + search: { default: "google", engines: { google: "https://google.com/search?q={}", }, - }), - properties: Properties.fromJSON({ + }, + properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, complete: "sbh" - }), - blacklist: Blacklist.fromJSON([]), - }; + }, + blacklist: [], + }); let json = JSONTextSettings.fromSettings(o).toJSONText(); expect(JSON.parse(json)).to.deep.equal({ @@ -150,24 +147,24 @@ describe('shared/SettingData', () => { describe('#fromSettings to #toJSON', () => { it('create from a Settings and create a JSON string', () => { - let data: Settings = { - keymaps: Keymaps.fromJSON({ + let data: Settings = Settings.fromJSON({ + keymaps: { 'j': { type: 'scroll.vertically', count: 1 }, '0': { type: 'scroll.home' }, - }), - search: Search.fromJSON({ + }, + search: { default: "google", engines: { "google": "https://google.com/search?q={}" } - }), - properties: Properties.fromJSON({ + }, + properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, complete: "sbh" - }), - blacklist: Blacklist.fromJSON([]), - }; + }, + blacklist: [], + }); let json = FormSettings.fromSettings(data).toJSON(); expect(json).to.deep.equal({ diff --git a/test/shared/Settings.test.ts b/test/shared/Settings.test.ts deleted file mode 100644 index 9688798..0000000 --- a/test/shared/Settings.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as settings from '../../src/shared/Settings'; -import {expect} from 'chai'; - -describe('Settings', () => { - describe('#valueOf', () => { - it('returns settings by valid settings', () => { - let x = settings.valueOf({ - keymaps: {}, - "search": { - "default": "google", - "engines": { - "google": "https://google.com/search?q={}", - } - }, - "properties": {}, - "blacklist": [] - }); - - expect({ - keymaps: x.keymaps.toJSON(), - search: x.search.toJSON(), - properties: x.properties.toJSON(), - blacklist: x.blacklist.toJSON(), - }).to.deep.equal({ - keymaps: {}, - search: { - default: "google", - engines: { - google: "https://google.com/search?q={}", - } - }, - properties: { - hintchars: "abcdefghijklmnopqrstuvwxyz", - smoothscroll: false, - complete: "sbh" - }, - blacklist: [] - }); - }); - - it('sets default settings', () => { - let value = settings.valueOf({}); - expect(value.keymaps.toJSON()).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.toJSON()).to.be.empty; - }); - - it('throws a TypeError with an unknown field', () => { - expect(() => settings.valueOf({ name: 'alice' })).to.throw(TypeError) - }); - }); -}); diff --git a/test/shared/settings/Settings.test.ts b/test/shared/settings/Settings.test.ts new file mode 100644 index 0000000..ab6af04 --- /dev/null +++ b/test/shared/settings/Settings.test.ts @@ -0,0 +1,54 @@ +import Settings from '../../../src/shared/settings/Settings'; +import { expect } from 'chai'; + +describe('Settings', () => { + describe('#valueOf', () => { + it('returns settings by valid settings', () => { + let x = Settings.fromJSON({ + keymaps: {}, + "search": { + "default": "google", + "engines": { + "google": "https://google.com/search?q={}", + } + }, + "properties": {}, + "blacklist": [] + }); + + expect({ + keymaps: x.keymaps.toJSON(), + search: x.search.toJSON(), + properties: x.properties.toJSON(), + blacklist: x.blacklist.toJSON(), + }).to.deep.equal({ + keymaps: {}, + search: { + default: "google", + engines: { + google: "https://google.com/search?q={}", + } + }, + properties: { + hintchars: "abcdefghijklmnopqrstuvwxyz", + smoothscroll: false, + complete: "sbh" + }, + blacklist: [] + }); + }); + + it('sets default settings', () => { + let value = Settings.fromJSON({}); + expect(value.keymaps.toJSON()).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.toJSON()).to.be.empty; + }); + + it('throws a TypeError with an unknown field', () => { + expect(() => Settings.fromJSON({ name: 'alice' })).to.throw(TypeError) + }); + }); +}); -- cgit v1.2.3