parent
410ffbb037
commit
2116ac90a6
9 changed files with 182 additions and 130 deletions
@ -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]; |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
}); |
||||||
|
}); |
Reference in new issue