Merge pull request #654 from ueokande/settings-as-a-class
Refactor settings on shared logicsjh-changes
commit
8eddcc1785
67 changed files with 1315 additions and 1288 deletions
@ -1,72 +0,0 @@ |
||||
export default interface Key { |
||||
key: string; |
||||
shiftKey?: boolean; |
||||
ctrlKey?: boolean; |
||||
altKey?: boolean; |
||||
metaKey?: boolean; |
||||
} |
||||
|
||||
const modifiedKeyName = (name: string): string => { |
||||
if (name === ' ') { |
||||
return 'Space'; |
||||
} |
||||
if (name.length === 1) { |
||||
return name; |
||||
} else if (name === 'Escape') { |
||||
return 'Esc'; |
||||
} |
||||
return name; |
||||
}; |
||||
|
||||
export const fromKeyboardEvent = (e: KeyboardEvent): Key => { |
||||
let key = modifiedKeyName(e.key); |
||||
let shift = e.shiftKey; |
||||
if (key.length === 1 && key.toUpperCase() === key.toLowerCase()) { |
||||
// make shift false for symbols to enable key bindings by symbold keys.
|
||||
// But this limits key bindings by symbol keys with Shift (such as Shift+$>.
|
||||
shift = false; |
||||
} |
||||
|
||||
return { |
||||
key: modifiedKeyName(e.key), |
||||
shiftKey: shift, |
||||
ctrlKey: e.ctrlKey, |
||||
altKey: e.altKey, |
||||
metaKey: e.metaKey, |
||||
}; |
||||
}; |
||||
|
||||
export const fromMapKey = (key: string): Key => { |
||||
if (key.startsWith('<') && key.endsWith('>')) { |
||||
let inner = key.slice(1, -1); |
||||
let shift = inner.includes('S-'); |
||||
let base = inner.slice(inner.lastIndexOf('-') + 1); |
||||
if (shift && base.length === 1) { |
||||
base = base.toUpperCase(); |
||||
} else if (!shift && base.length === 1) { |
||||
base = base.toLowerCase(); |
||||
} |
||||
return { |
||||
key: base, |
||||
shiftKey: inner.includes('S-'), |
||||
ctrlKey: inner.includes('C-'), |
||||
altKey: inner.includes('A-'), |
||||
metaKey: inner.includes('M-'), |
||||
}; |
||||
} |
||||
return { |
||||
key: key, |
||||
shiftKey: key.toLowerCase() !== key, |
||||
ctrlKey: false, |
||||
altKey: false, |
||||
metaKey: false, |
||||
}; |
||||
}; |
||||
|
||||
export const equals = (e1: Key, e2: Key): boolean => { |
||||
return e1.key === e2.key && |
||||
e1.ctrlKey === e2.ctrlKey && |
||||
e1.metaKey === e2.metaKey && |
||||
e1.altKey === e2.altKey && |
||||
e1.shiftKey === e2.shiftKey; |
||||
}; |
@ -1,64 +0,0 @@ |
||||
import Key, * as keyUtils from './Key'; |
||||
|
||||
export default class KeySequence { |
||||
private keys: Key[]; |
||||
|
||||
private constructor(keys: Key[]) { |
||||
this.keys = keys; |
||||
} |
||||
|
||||
static from(keys: Key[]): KeySequence { |
||||
return new KeySequence(keys); |
||||
} |
||||
|
||||
push(key: Key): number { |
||||
return this.keys.push(key); |
||||
} |
||||
|
||||
length(): number { |
||||
return this.keys.length; |
||||
} |
||||
|
||||
startsWith(o: KeySequence): boolean { |
||||
if (this.keys.length < o.keys.length) { |
||||
return false; |
||||
} |
||||
for (let i = 0; i < o.keys.length; ++i) { |
||||
if (!keyUtils.equals(this.keys[i], o.keys[i])) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
getKeyArray(): Key[] { |
||||
return this.keys; |
||||
} |
||||
} |
||||
|
||||
export const fromMapKeys = (keys: string): KeySequence => { |
||||
const fromMapKeysRecursive = ( |
||||
remainings: string, mappedKeys: Key[], |
||||
): Key[] => { |
||||
if (remainings.length === 0) { |
||||
return mappedKeys; |
||||
} |
||||
|
||||
let nextPos = 1; |
||||
if (remainings.startsWith('<')) { |
||||
let ltPos = remainings.indexOf('>'); |
||||
if (ltPos > 0) { |
||||
nextPos = ltPos + 1; |
||||
} |
||||
} |
||||
|
||||
return fromMapKeysRecursive( |
||||
remainings.slice(nextPos), |
||||
mappedKeys.concat([keyUtils.fromMapKey(remainings.slice(0, nextPos))]) |
||||
); |
||||
}; |
||||
|
||||
let data = fromMapKeysRecursive(keys, []); |
||||
return KeySequence.from(data); |
||||
}; |
||||
|
@ -1,200 +0,0 @@ |
||||
import * as operations from './operations'; |
||||
import * as PropertyDefs from './property-defs'; |
||||
|
||||
export type Keymaps = {[key: string]: operations.Operation}; |
||||
|
||||
export interface Search { |
||||
default: string; |
||||
engines: { [key: string]: string }; |
||||
} |
||||
|
||||
export interface Properties { |
||||
hintchars: string; |
||||
smoothscroll: boolean; |
||||
complete: string; |
||||
} |
||||
|
||||
export default interface Settings { |
||||
keymaps: Keymaps; |
||||
search: Search; |
||||
properties: Properties; |
||||
blacklist: string[]; |
||||
} |
||||
|
||||
export const keymapsValueOf = (o: any): Keymaps => { |
||||
return Object.keys(o).reduce((keymaps: Keymaps, key: string): Keymaps => { |
||||
let op = operations.valueOf(o[key]); |
||||
keymaps[key] = op; |
||||
return keymaps; |
||||
}, {}); |
||||
}; |
||||
|
||||
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)); |
||||
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`); |
||||
} |
||||
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)) { |
||||
switch (key) { |
||||
case 'keymaps': |
||||
settings.keymaps = keymapsValueOf(o.keymaps); |
||||
break; |
||||
case 'search': |
||||
settings.search = searchValueOf(o.search); |
||||
break; |
||||
case 'properties': |
||||
settings.properties = propertiesValueOf(o.properties); |
||||
break; |
||||
case 'blacklist': |
||||
settings.blacklist = blacklistValueOf(o.blacklist); |
||||
break; |
||||
default: |
||||
throw new TypeError('unknown setting: ' + key); |
||||
} |
||||
} |
||||
return settings; |
||||
}; |
||||
|
||||
export const DefaultSetting: Settings = { |
||||
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 }, |
||||
'<C-U>': { 'type': 'scroll.pages', 'count': -0.5 }, |
||||
'<C-D>': { 'type': 'scroll.pages', 'count': 0.5 }, |
||||
'<C-B>': { 'type': 'scroll.pages', 'count': -1 }, |
||||
'<C-F>': { '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' }, |
||||
'<C-6>': { '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' }, |
||||
'<S-Esc>': { '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: [] |
||||
}; |
@ -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 }; |
@ -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'), |
||||
]; |
@ -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', |
||||
}; |
@ -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); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,61 @@ |
||||
export default class Key { |
||||
public readonly key: string; |
||||
|
||||
public readonly shift: boolean; |
||||
|
||||
public readonly ctrl: boolean; |
||||
|
||||
public readonly alt: boolean; |
||||
|
||||
public readonly meta: boolean; |
||||
|
||||
constructor({ key, shift, ctrl, alt, meta }: { |
||||
key: string; |
||||
shift: boolean; |
||||
ctrl: boolean; |
||||
alt: boolean; |
||||
meta: boolean; |
||||
}) { |
||||
this.key = key; |
||||
this.shift = shift; |
||||
this.ctrl = ctrl; |
||||
this.alt = alt; |
||||
this.meta = meta; |
||||
} |
||||
|
||||
static fromMapKey(str: string): Key { |
||||
if (str.startsWith('<') && str.endsWith('>')) { |
||||
let inner = str.slice(1, -1); |
||||
let shift = inner.includes('S-'); |
||||
let base = inner.slice(inner.lastIndexOf('-') + 1); |
||||
if (shift && base.length === 1) { |
||||
base = base.toUpperCase(); |
||||
} else if (!shift && base.length === 1) { |
||||
base = base.toLowerCase(); |
||||
} |
||||
return new Key({ |
||||
key: base, |
||||
shift: shift, |
||||
ctrl: inner.includes('C-'), |
||||
alt: inner.includes('A-'), |
||||
meta: inner.includes('M-'), |
||||
}); |
||||
} |
||||
|
||||
return new Key({ |
||||
key: str, |
||||
shift: str.toLowerCase() !== str, |
||||
ctrl: false, |
||||
alt: false, |
||||
meta: false, |
||||
}); |
||||
} |
||||
|
||||
equals(key: Key) { |
||||
return this.key === key.key && |
||||
this.ctrl === key.ctrl && |
||||
this.meta === key.meta && |
||||
this.alt === key.alt && |
||||
this.shift === key.shift; |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
import Key from '../../shared/settings/Key'; |
||||
|
||||
export default class KeySequence { |
||||
constructor( |
||||
public readonly keys: Key[], |
||||
) { |
||||
} |
||||
|
||||
push(key: Key): number { |
||||
return this.keys.push(key); |
||||
} |
||||
|
||||
length(): number { |
||||
return this.keys.length; |
||||
} |
||||
|
||||
startsWith(o: KeySequence): boolean { |
||||
if (this.keys.length < o.keys.length) { |
||||
return false; |
||||
} |
||||
for (let i = 0; i < o.keys.length; ++i) { |
||||
if (!this.keys[i].equals(o.keys[i])) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static fromMapKeys(keys: string): KeySequence { |
||||
const fromMapKeysRecursive = ( |
||||
remaining: string, mappedKeys: Key[], |
||||
): Key[] => { |
||||
if (remaining.length === 0) { |
||||
return mappedKeys; |
||||
} |
||||
|
||||
let nextPos = 1; |
||||
if (remaining.startsWith('<')) { |
||||
let ltPos = remaining.indexOf('>'); |
||||
if (ltPos > 0) { |
||||
nextPos = ltPos + 1; |
||||
} |
||||
} |
||||
|
||||
return fromMapKeysRecursive( |
||||
remaining.slice(nextPos), |
||||
mappedKeys.concat([Key.fromMapKey(remaining.slice(0, nextPos))]) |
||||
); |
||||
}; |
||||
|
||||
let data = fromMapKeysRecursive(keys, []); |
||||
return new KeySequence(data); |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
import * as operations from '../operations'; |
||||
|
||||
export type KeymapsJSON = { [key: string]: operations.Operation }; |
||||
|
||||
export default class Keymaps { |
||||
constructor( |
||||
private readonly data: KeymapsJSON, |
||||
) { |
||||
} |
||||
|
||||
static fromJSON(json: any): Keymaps { |
||||
if (typeof json !== 'object' || json === null) { |
||||
throw new TypeError('invalid keymaps type: ' + JSON.stringify(json)); |
||||
} |
||||
|
||||
let data: KeymapsJSON = {}; |
||||
for (let key of Object.keys(json)) { |
||||
data[key] = operations.valueOf(json[key]); |
||||
} |
||||
return new Keymaps(data); |
||||
} |
||||
|
||||
combine(other: Keymaps): Keymaps { |
||||
return new Keymaps({ |
||||
...this.data, |
||||
...other.data, |
||||
}); |
||||
} |
||||
|
||||
toJSON(): KeymapsJSON { |
||||
return this.data; |
||||
} |
||||
|
||||
entries(): [string, operations.Operation][] { |
||||
return Object.entries(this.data); |
||||
} |
||||
} |
@ -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<string> = 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, |
||||
}; |
||||
} |
||||
} |
@ -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,158 @@ |
||||
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 DefaultSettingJSONText = `{
|
||||
"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 }, |
||||
"<C-U>": { "type": "scroll.pages", "count": -0.5 }, |
||||
"<C-D>": { "type": "scroll.pages", "count": 0.5 }, |
||||
"<C-B>": { "type": "scroll.pages", "count": -1 }, |
||||
"<C-F>": { "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" }, |
||||
"<C-6>": { "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 }, |
||||
"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" }, |
||||
"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" }, |
||||
"<S-Esc>": { "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": [ |
||||
] |
||||
}`;
|
||||
|
||||
export const DefaultSetting: Settings = |
||||
Settings.fromJSON(JSON.parse(DefaultSettingJSONText)); |
@ -1,6 +0,0 @@ |
||||
const fromWildcard = (pattern: string): RegExp => { |
||||
let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$'; |
||||
return new RegExp(regexStr); |
||||
}; |
||||
|
||||
export { fromWildcard }; |
@ -1,137 +0,0 @@ |
||||
import Key, * as keys from '../../../src/content/domains/Key'; |
||||
import { expect } from 'chai' |
||||
|
||||
describe("Key", () => { |
||||
describe('fromKeyboardEvent', () => { |
||||
it('returns from keyboard input Ctrl+X', () => { |
||||
let k = keys.fromKeyboardEvent(new KeyboardEvent('keydown', { |
||||
key: 'x', shiftKey: false, ctrlKey: true, altKey: false, metaKey: true, |
||||
})); |
||||
expect(k.key).to.equal('x'); |
||||
expect(k.shiftKey).to.be.false; |
||||
expect(k.ctrlKey).to.be.true; |
||||
expect(k.altKey).to.be.false; |
||||
expect(k.metaKey).to.be.true; |
||||
}); |
||||
|
||||
it('returns from keyboard input Shift+Esc', () => { |
||||
let k = keys.fromKeyboardEvent(new KeyboardEvent('keydown', { |
||||
key: 'Escape', shiftKey: true, ctrlKey: false, altKey: false, metaKey: true |
||||
})); |
||||
expect(k.key).to.equal('Esc'); |
||||
expect(k.shiftKey).to.be.true; |
||||
expect(k.ctrlKey).to.be.false; |
||||
expect(k.altKey).to.be.false; |
||||
expect(k.metaKey).to.be.true; |
||||
}); |
||||
|
||||
it('returns from keyboard input Ctrl+$', () => { |
||||
// $ required shift pressing on most keyboards
|
||||
let k = keys.fromKeyboardEvent(new KeyboardEvent('keydown', { |
||||
key: '$', shiftKey: true, ctrlKey: true, altKey: false, metaKey: false |
||||
})); |
||||
expect(k.key).to.equal('$'); |
||||
expect(k.shiftKey).to.be.false; |
||||
expect(k.ctrlKey).to.be.true; |
||||
expect(k.altKey).to.be.false; |
||||
expect(k.metaKey).to.be.false; |
||||
}); |
||||
|
||||
it('returns from keyboard input Crtl+Space', () => { |
||||
let k = keys.fromKeyboardEvent(new KeyboardEvent('keydown', { |
||||
key: ' ', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false |
||||
})); |
||||
expect(k.key).to.equal('Space'); |
||||
expect(k.shiftKey).to.be.false; |
||||
expect(k.ctrlKey).to.be.true; |
||||
expect(k.altKey).to.be.false; |
||||
expect(k.metaKey).to.be.false; |
||||
}); |
||||
}); |
||||
|
||||
describe('fromMapKey', () => { |
||||
it('return for X', () => { |
||||
let key = keys.fromMapKey('x'); |
||||
expect(key.key).to.equal('x'); |
||||
expect(key.shiftKey).to.be.false; |
||||
expect(key.ctrlKey).to.be.false; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.false; |
||||
}); |
||||
|
||||
it('return for Shift+X', () => { |
||||
let key = keys.fromMapKey('X'); |
||||
expect(key.key).to.equal('X'); |
||||
expect(key.shiftKey).to.be.true; |
||||
expect(key.ctrlKey).to.be.false; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.false; |
||||
}); |
||||
|
||||
it('return for Ctrl+X', () => { |
||||
let key = keys.fromMapKey('<C-X>'); |
||||
expect(key.key).to.equal('x'); |
||||
expect(key.shiftKey).to.be.false; |
||||
expect(key.ctrlKey).to.be.true; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Meta+X', () => { |
||||
let key = keys.fromMapKey('<C-M-X>'); |
||||
expect(key.key).to.equal('x'); |
||||
expect(key.shiftKey).to.be.false; |
||||
expect(key.ctrlKey).to.be.true; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.true; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Shift+x', () => { |
||||
let key = keys.fromMapKey('<C-S-x>'); |
||||
expect(key.key).to.equal('X'); |
||||
expect(key.shiftKey).to.be.true; |
||||
expect(key.ctrlKey).to.be.true; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Shift+Esc', () => { |
||||
let key = keys.fromMapKey('<S-Esc>'); |
||||
expect(key.key).to.equal('Esc'); |
||||
expect(key.shiftKey).to.be.true; |
||||
expect(key.ctrlKey).to.be.false; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Esc', () => { |
||||
let key = keys.fromMapKey('<C-Esc>'); |
||||
expect(key.key).to.equal('Esc'); |
||||
expect(key.shiftKey).to.be.false; |
||||
expect(key.ctrlKey).to.be.true; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Esc', () => { |
||||
let key = keys.fromMapKey('<C-Space>'); |
||||
expect(key.key).to.equal('Space'); |
||||
expect(key.shiftKey).to.be.false; |
||||
expect(key.ctrlKey).to.be.true; |
||||
expect(key.altKey).to.be.false; |
||||
expect(key.metaKey).to.be.false; |
||||
}); |
||||
}); |
||||
|
||||
describe('equals', () => { |
||||
expect(keys.equals( |
||||
{ key: 'x', ctrlKey: true, }, |
||||
{ key: 'x', ctrlKey: true, }, |
||||
)).to.be.true; |
||||
|
||||
expect(keys.equals( |
||||
{ key: 'X', shiftKey: true, }, |
||||
{ key: 'x', ctrlKey: true, }, |
||||
)).to.be.false; |
||||
}); |
||||
}); |
@ -1,72 +0,0 @@ |
||||
import KeySequence, * as utils from '../../../src/content/domains/KeySequence'; |
||||
import { expect } from 'chai' |
||||
|
||||
describe("KeySequence", () => { |
||||
describe('#push', () => { |
||||
it('append a key to the sequence', () => { |
||||
let seq = KeySequence.from([]); |
||||
seq.push({ key: 'g' }); |
||||
seq.push({ key: 'u', shiftKey: true }); |
||||
|
||||
let array = seq.getKeyArray(); |
||||
expect(array[0]).to.deep.equal({ key: 'g' }); |
||||
expect(array[1]).to.deep.equal({ key: 'u', shiftKey: true }); |
||||
}) |
||||
}); |
||||
|
||||
describe('#startsWith', () => { |
||||
it('returns true if the key sequence starts with param', () => { |
||||
let seq = KeySequence.from([ |
||||
{ key: 'g' }, |
||||
{ key: 'u', shiftKey: true }, |
||||
]); |
||||
|
||||
expect(seq.startsWith(KeySequence.from([ |
||||
]))).to.be.true; |
||||
expect(seq.startsWith(KeySequence.from([ |
||||
{ key: 'g' }, |
||||
]))).to.be.true; |
||||
expect(seq.startsWith(KeySequence.from([ |
||||
{ key: 'g' }, { key: 'u', shiftKey: true }, |
||||
]))).to.be.true; |
||||
expect(seq.startsWith(KeySequence.from([ |
||||
{ key: 'g' }, { key: 'u', shiftKey: true }, { key: 'x' }, |
||||
]))).to.be.false; |
||||
expect(seq.startsWith(KeySequence.from([ |
||||
{ key: 'h' }, |
||||
]))).to.be.false; |
||||
}) |
||||
|
||||
it('returns true if the empty sequence starts with an empty sequence', () => { |
||||
let seq = KeySequence.from([]); |
||||
|
||||
expect(seq.startsWith(KeySequence.from([]))).to.be.true; |
||||
expect(seq.startsWith(KeySequence.from([ |
||||
{ key: 'h' }, |
||||
]))).to.be.false; |
||||
}) |
||||
}); |
||||
|
||||
describe('#fromMapKeys', () => { |
||||
it('returns mapped keys for Shift+Esc', () => { |
||||
let keyArray = utils.fromMapKeys('<S-Esc>').getKeyArray(); |
||||
expect(keyArray).to.have.lengthOf(1); |
||||
expect(keyArray[0].key).to.equal('Esc'); |
||||
expect(keyArray[0].shiftKey).to.be.true; |
||||
}); |
||||
|
||||
it('returns mapped keys for a<C-B><A-C>d<M-e>', () => { |
||||
let keyArray = utils.fromMapKeys('a<C-B><A-C>d<M-e>').getKeyArray(); |
||||
expect(keyArray).to.have.lengthOf(5); |
||||
expect(keyArray[0].key).to.equal('a'); |
||||
expect(keyArray[1].ctrlKey).to.be.true; |
||||
expect(keyArray[1].key).to.equal('b'); |
||||
expect(keyArray[2].altKey).to.be.true; |
||||
expect(keyArray[2].key).to.equal('c'); |
||||
expect(keyArray[3].key).to.equal('d'); |
||||
expect(keyArray[4].metaKey).to.be.true; |
||||
expect(keyArray[4].key).to.equal('e'); |
||||
}); |
||||
}) |
||||
|
||||
}); |
@ -1,194 +0,0 @@ |
||||
import * as settings from '../../src/shared/Settings'; |
||||
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({ |
||||
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', () => { |
||||
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" |
||||
}); |
||||
}); |
||||
|
||||
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', () => { |
||||
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({ |
||||
keymaps: {}, |
||||
"search": { |
||||
"default": "google", |
||||
"engines": { |
||||
"google": "https://google.com/search?q={}", |
||||
} |
||||
}, |
||||
"properties": {}, |
||||
"blacklist": [] |
||||
}); |
||||
|
||||
expect(x).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).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'); |
||||
expect(value.blacklist).to.be.empty; |
||||
}); |
||||
|
||||
it('throws a TypeError with an unknown field', () => { |
||||
expect(() => settings.valueOf({ name: 'alice' })).to.throw(TypeError) |
||||
}); |
||||
}); |
||||
}); |
@ -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; |
||||
}) |
||||
}); |
@ -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'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
@ -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'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
@ -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; |
||||
}) |
||||
}) |
||||
}); |
@ -0,0 +1,92 @@ |
||||
import { expect } from 'chai' |
||||
import Key from '../../../src/shared/settings/Key'; |
||||
|
||||
describe("Key", () => { |
||||
describe('fromMapKey', () => { |
||||
it('return for X', () => { |
||||
let key = Key.fromMapKey('x'); |
||||
expect(key.key).to.equal('x'); |
||||
expect(key.shift).to.be.false; |
||||
expect(key.ctrl).to.be.false; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.false; |
||||
}); |
||||
|
||||
it('return for Shift+X', () => { |
||||
let key = Key.fromMapKey('X'); |
||||
expect(key.key).to.equal('X'); |
||||
expect(key.shift).to.be.true; |
||||
expect(key.ctrl).to.be.false; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.false; |
||||
}); |
||||
|
||||
it('return for Ctrl+X', () => { |
||||
let key = Key.fromMapKey('<C-X>'); |
||||
expect(key.key).to.equal('x'); |
||||
expect(key.shift).to.be.false; |
||||
expect(key.ctrl).to.be.true; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Meta+X', () => { |
||||
let key = Key.fromMapKey('<C-M-X>'); |
||||
expect(key.key).to.equal('x'); |
||||
expect(key.shift).to.be.false; |
||||
expect(key.ctrl).to.be.true; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.true; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Shift+x', () => { |
||||
let key = Key.fromMapKey('<C-S-x>'); |
||||
expect(key.key).to.equal('X'); |
||||
expect(key.shift).to.be.true; |
||||
expect(key.ctrl).to.be.true; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Shift+Esc', () => { |
||||
let key = Key.fromMapKey('<S-Esc>'); |
||||
expect(key.key).to.equal('Esc'); |
||||
expect(key.shift).to.be.true; |
||||
expect(key.ctrl).to.be.false; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Esc', () => { |
||||
let key = Key.fromMapKey('<C-Esc>'); |
||||
expect(key.key).to.equal('Esc'); |
||||
expect(key.shift).to.be.false; |
||||
expect(key.ctrl).to.be.true; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.false; |
||||
}); |
||||
|
||||
it('returns for Ctrl+Esc', () => { |
||||
let key = Key.fromMapKey('<C-Space>'); |
||||
expect(key.key).to.equal('Space'); |
||||
expect(key.shift).to.be.false; |
||||
expect(key.ctrl).to.be.true; |
||||
expect(key.alt).to.be.false; |
||||
expect(key.meta).to.be.false; |
||||
}); |
||||
}); |
||||
|
||||
describe('equals', () => { |
||||
expect(new Key({ |
||||
key: 'x', shift: false, ctrl: true, alt: false, meta: false, |
||||
}).equals(new Key({ |
||||
key: 'x', shift: false, ctrl: true, alt: false, meta: false, |
||||
}))).to.be.true; |
||||
|
||||
expect(new Key({ |
||||
key: 'x', shift: false, ctrl: false, alt: false, meta: false, |
||||
}).equals(new Key({ |
||||
key: 'X', shift: true, ctrl: false, alt: false, meta: false, |
||||
}))).to.be.false; |
||||
}); |
||||
}); |
@ -0,0 +1,72 @@ |
||||
import KeySequence from '../../../src/shared/settings/KeySequence'; |
||||
import { expect } from 'chai' |
||||
import Key from "../../../src/shared/settings/Key"; |
||||
|
||||
describe("KeySequence", () => { |
||||
describe('#push', () => { |
||||
it('append a key to the sequence', () => { |
||||
let seq = new KeySequence([]); |
||||
seq.push(Key.fromMapKey('g')); |
||||
seq.push(Key.fromMapKey('<S-U>')); |
||||
|
||||
expect(seq.keys[0].key).to.equal('g'); |
||||
expect(seq.keys[1].key).to.equal('U'); |
||||
expect(seq.keys[1].shift).to.be.true; |
||||
}) |
||||
}); |
||||
|
||||
describe('#startsWith', () => { |
||||
it('returns true if the key sequence starts with param', () => { |
||||
let seq = new KeySequence([ |
||||
Key.fromMapKey('g'), |
||||
Key.fromMapKey('<S-U>'), |
||||
]); |
||||
|
||||
expect(seq.startsWith(new KeySequence([ |
||||
]))).to.be.true; |
||||
expect(seq.startsWith(new KeySequence([ |
||||
Key.fromMapKey('g'), |
||||
]))).to.be.true; |
||||
expect(seq.startsWith(new KeySequence([ |
||||
Key.fromMapKey('g'), Key.fromMapKey('<S-U>'), |
||||
]))).to.be.true; |
||||
expect(seq.startsWith(new KeySequence([ |
||||
Key.fromMapKey('g'), Key.fromMapKey('<S-U>'), Key.fromMapKey('x'), |
||||
]))).to.be.false; |
||||
expect(seq.startsWith(new KeySequence([ |
||||
Key.fromMapKey('h'), |
||||
]))).to.be.false; |
||||
}); |
||||
|
||||
it('returns true if the empty sequence starts with an empty sequence', () => { |
||||
let seq = new KeySequence([]); |
||||
|
||||
expect(seq.startsWith(new KeySequence([]))).to.be.true; |
||||
expect(seq.startsWith(new KeySequence([ |
||||
Key.fromMapKey('h'), |
||||
]))).to.be.false; |
||||
}) |
||||
}); |
||||
|
||||
describe('#fromMapKeys', () => { |
||||
it('returns mapped keys for Shift+Esc', () => { |
||||
let keys = KeySequence.fromMapKeys('<S-Esc>').keys; |
||||
expect(keys).to.have.lengthOf(1); |
||||
expect(keys[0].key).to.equal('Esc'); |
||||
expect(keys[0].shift).to.be.true; |
||||
}); |
||||
|
||||
it('returns mapped keys for a<C-B><A-C>d<M-e>', () => { |
||||
let keys = KeySequence.fromMapKeys('a<C-B><A-C>d<M-e>').keys; |
||||
expect(keys).to.have.lengthOf(5); |
||||
expect(keys[0].key).to.equal('a'); |
||||
expect(keys[1].ctrl).to.be.true; |
||||
expect(keys[1].key).to.equal('b'); |
||||
expect(keys[2].alt).to.be.true; |
||||
expect(keys[2].key).to.equal('c'); |
||||
expect(keys[3].key).to.equal('d'); |
||||
expect(keys[4].meta).to.be.true; |
||||
expect(keys[4].key).to.equal('e'); |
||||
}); |
||||
}) |
||||
}); |
@ -0,0 +1,66 @@ |
||||
import Keymaps from '../../../src/shared/settings/Keymaps'; |
||||
import { expect } from 'chai'; |
||||
|
||||
describe('Keymaps', () => { |
||||
describe('#valueOf', () => { |
||||
it('returns empty object by empty settings', () => { |
||||
let keymaps = Keymaps.fromJSON({}).toJSON(); |
||||
expect(keymaps).to.be.empty; |
||||
}); |
||||
|
||||
it('returns keymaps by valid settings', () => { |
||||
let keymaps = Keymaps.fromJSON({ |
||||
k: { type: "scroll.vertically", count: -1 }, |
||||
j: { type: "scroll.vertically", count: 1 }, |
||||
}).toJSON(); |
||||
|
||||
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(() => Keymaps.fromJSON(null)).to.throw(TypeError); |
||||
expect(() => Keymaps.fromJSON({ |
||||
k: { type: "invalid.operation" }, |
||||
})).to.throw(TypeError); |
||||
}); |
||||
}); |
||||
|
||||
describe('#combine', () => { |
||||
it('returns combined keymaps', () => { |
||||
let keymaps = Keymaps.fromJSON({ |
||||
k: { type: "scroll.vertically", count: -1 }, |
||||
j: { type: "scroll.vertically", count: 1 }, |
||||
}).combine(Keymaps.fromJSON({ |
||||
n: { type: "find.next" }, |
||||
N: { type: "find.prev" }, |
||||
})); |
||||
|
||||
let entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2)); |
||||
expect(entries).deep.equals([ |
||||
['j', { type: "scroll.vertically", count: 1 }], |
||||
['k', { type: "scroll.vertically", count: -1 }], |
||||
['n', { type: "find.next" }], |
||||
['N', { type: "find.prev" }], |
||||
]); |
||||
}); |
||||
|
||||
it('overrides current keymaps', () => { |
||||
let keymaps = Keymaps.fromJSON({ |
||||
k: { type: "scroll.vertically", count: -1 }, |
||||
j: { type: "scroll.vertically", count: 1 }, |
||||
}).combine(Keymaps.fromJSON({ |
||||
n: { type: "find.next" }, |
||||
j: { type: "find.prev" }, |
||||
})); |
||||
|
||||
let entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2)); |
||||
expect(entries).deep.equals([ |
||||
['j', { type: "find.prev" }], |
||||
['k', { type: "scroll.vertically", count: -1 }], |
||||
['n', { type: "find.next" }], |
||||
]); |
||||
}); |
||||
}); |
||||
}); |
||||
|
@ -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" |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
@ -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); |
||||
}); |
||||
}); |
@ -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) |
||||
}); |
||||
}); |
||||
}); |
@ -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); |
||||
}) |
||||
}); |
Reference in new issue