Make Search class

This commit is contained in:
Shin'ya UEOKA 2019-10-05 01:08:07 +00:00
parent 410ffbb037
commit 2116ac90a6
9 changed files with 182 additions and 130 deletions

View file

@ -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,
});

View file

@ -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' },
'<S-Esc>': { '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,

View file

@ -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];
}
}

View file

@ -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];