diff options
| author | Shin'ya Ueoka <ueokande@i-beam.org> | 2018-01-11 20:07:25 +0900 | 
|---|---|---|
| committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2018-01-11 20:07:25 +0900 | 
| commit | dda4e7475cdd092d00441c7cd0ceb194ee5dee3d (patch) | |
| tree | d1bd538de2efb8243a55d80ece4ed5a63feb058d | |
| parent | 22c34a0a6f9721fb9d907ab10de91cbbc40d6bbe (diff) | |
move commands to background action
| -rw-r--r-- | src/background/actions/command.js (renamed from src/shared/commands/exec.js) | 37 | ||||
| -rw-r--r-- | src/background/components/background.js | 3 | ||||
| -rw-r--r-- | src/shared/commands/index.js | 3 | ||||
| -rw-r--r-- | src/shared/commands/parsers.js | 59 | ||||
| -rw-r--r-- | src/shared/commands/properties.js | 31 | ||||
| -rw-r--r-- | test/shared/commands/parsers.test.js | 78 | ||||
| -rw-r--r-- | test/shared/commands/property.test.js | 41 | 
7 files changed, 147 insertions, 105 deletions
diff --git a/src/shared/commands/exec.js b/src/background/actions/command.js index 7248827..f11c61b 100644 --- a/src/shared/commands/exec.js +++ b/src/background/actions/command.js @@ -1,27 +1,5 @@  import * as tabs from 'background/tabs'; -import * as histories from 'background/histories'; - -const normalizeUrl = (args, searchConfig) => { -  let concat = args.join(' '); -  try { -    return new URL(concat).href; -  } catch (e) { -    if (concat.includes('.') && !concat.includes(' ')) { -      return 'http://' + concat; -    } -    let query = concat; -    let template = searchConfig.engines[ -      searchConfig.default -    ]; -    for (let key in searchConfig.engines) { -      if (args[0] === key) { -        query = args.slice(1).join(' '); -        template = searchConfig.engines[key]; -      } -    } -    return template.replace('{}', encodeURIComponent(query)); -  } -}; +import * as parsers from 'shared/commands/parsers';  const openCommand = (url) => {    return browser.tabs.query({ @@ -60,26 +38,25 @@ const bufferCommand = (keywords) => {  };  const exec = (line, settings) => { -  let words = line.trim().split(/ +/); -  let name = words.shift(); +  let [name, args] = parsers.parseCommandLine(line);    switch (name) {    case 'o':    case 'open': -    return openCommand(normalizeUrl(words, settings.search)); +    return openCommand(parsers.normalizeUrl(args, settings.search));    case 't':    case 'tabopen': -    return tabopenCommand(normalizeUrl(words, settings.search)); +    return tabopenCommand(parsers.normalizeUrl(args, settings.search));    case 'w':    case 'winopen': -    return winopenCommand(normalizeUrl(words, settings.search)); +    return winopenCommand(parsers.normalizeUrl(args, settings.search));    case 'b':    case 'buffer': -    return bufferCommand(words); +    return bufferCommand(args);    case '':      return Promise.resolve();    }    throw new Error(name + ' command is not defined');  }; -export default exec; +export { exec }; diff --git a/src/background/components/background.js b/src/background/components/background.js index 22c6693..19bf27f 100644 --- a/src/background/components/background.js +++ b/src/background/components/background.js @@ -1,5 +1,6 @@  import messages from 'shared/messages';  import * as operationActions from 'background/actions/operation'; +import * as commandActions from 'background/actions/command';  import * as settingActions from 'background/actions/setting';  import * as tabActions from 'background/actions/tab';  import * as commands from 'shared/commands'; @@ -35,7 +36,7 @@ export default class BackgroundComponent {        return this.store.dispatch(          tabActions.openToTab(message.url, sender.tab), sender);      case messages.CONSOLE_ENTER_COMMAND: -      return commands.exec(message.text, settings.value).catch((e) => { +      return commandActions.exec(message.text, settings.value).catch((e) => {          return browser.tabs.sendMessage(sender.tab.id, {            type: messages.CONSOLE_SHOW_ERROR,            text: e.message, diff --git a/src/shared/commands/index.js b/src/shared/commands/index.js index c2cea3e..78cb4df 100644 --- a/src/shared/commands/index.js +++ b/src/shared/commands/index.js @@ -1,4 +1,3 @@ -import exec from './exec';  import complete from './complete'; -export { exec, complete }; +export { complete }; diff --git a/src/shared/commands/parsers.js b/src/shared/commands/parsers.js new file mode 100644 index 0000000..af51338 --- /dev/null +++ b/src/shared/commands/parsers.js @@ -0,0 +1,59 @@ +const normalizeUrl = (args, searchConfig) => { +  let concat = args.join(' '); +  try { +    return new URL(concat).href; +  } catch (e) { +    if (concat.includes('.') && !concat.includes(' ')) { +      return 'http://' + concat; +    } +    let query = concat; +    let template = searchConfig.engines[ +      searchConfig.default +    ]; +    for (let key in searchConfig.engines) { +      if (args[0] === key) { +        query = args.slice(1).join(' '); +        template = searchConfig.engines[key]; +      } +    } +    return template.replace('{}', encodeURIComponent(query)); +  } +}; + +const mustNumber = (v) => { +  let num = Number(v); +  if (isNaN(num)) { +    throw new Error('Not number: ' + v); +  } +  return num; +}; + +const parseSetOption = (word, types) => { +  let [key, value] = word.split('='); +  if (!value) { +    value = !key.startsWith('no'); +    key = value ? key : key.slice(2); +  } +  let type = types[key]; +  if (!type) { +    throw new Error('Unknown property: ' + key); +  } +  if (type === 'boolean' && typeof value !== 'boolean' || +       type !== 'boolean' && typeof value === 'boolean') { +    throw new Error('Invalid argument: ' + word); +  } + +  switch (type) { +  case 'string': return [key, value]; +  case 'number': return [key, mustNumber(value)]; +  case 'boolean': return [key, value]; +  } +}; + +const parseCommandLine = (line) => { +  let words = line.trim().split(/ +/); +  let name = words.shift(); +  return [name, words]; +}; + +export { normalizeUrl, parseCommandLine, parseSetOption }; diff --git a/src/shared/commands/properties.js b/src/shared/commands/properties.js deleted file mode 100644 index 8a3213d..0000000 --- a/src/shared/commands/properties.js +++ /dev/null @@ -1,31 +0,0 @@ -const mustNumber = (v) => { -  let num = Number(v); -  if (isNaN(num)) { -    throw new Error('Not number: ' + v); -  } -  return num; -}; - -const parseProperty = (word, types) => { -  let [key, value] = word.split('='); -  if (!value) { -    value = !key.startsWith('no'); -    key = value ? key : key.slice(2); -  } -  let type = types[key]; -  if (!type) { -    throw new Error('Unknown property: ' + key); -  } -  if (type === 'boolean' && typeof value !== 'boolean' || -       type !== 'boolean' && typeof value === 'boolean') { -    throw new Error('Invalid argument: ' + word); -  } - -  switch (type) { -  case 'string': return [key, value]; -  case 'number': return [key, mustNumber(value)]; -  case 'boolean': return [key, value]; -  } -}; - -export { parseProperty }; diff --git a/test/shared/commands/parsers.test.js b/test/shared/commands/parsers.test.js new file mode 100644 index 0000000..200323c --- /dev/null +++ b/test/shared/commands/parsers.test.js @@ -0,0 +1,78 @@ +import { expect } from "chai"; +import * as parsers from 'shared/commands/parsers'; + +describe("shared/commands/parsers", () => { +  describe("#parsers.parseSetOption", () => { +    it('parse set string', () => { +      let [key, value] = parsers.parseSetOption('encoding=utf-8', { encoding: 'string' }); +      expect(key).to.equal('encoding'); +      expect(value).to.equal('utf-8'); +    }); + +    it('parse set string', () => { +      let [key, value] = parsers.parseSetOption('history=50', { history: 'number' }); +      expect(key).to.equal('history'); +      expect(value).to.equal(50); +    }); + +    it('parse set boolean', () => { +      let [key, value] = parsers.parseSetOption('paste', { paste: 'boolean' }); +      expect(key).to.equal('paste'); +      expect(value).to.be.true; + +      [key, value] = parsers.parseSetOption('nopaste', { paste: 'boolean' }); +      expect(key).to.equal('paste'); +      expect(value).to.be.false; +    }); + +    it('throws error on unknown property', () => { +      expect(() => parsers.parseSetOption('charset=utf-8', {})).to.throw(Error, 'Unknown'); +      expect(() => parsers.parseSetOption('smoothscroll', {})).to.throw(Error, 'Unknown'); +      expect(() => parsers.parseSetOption('nosmoothscroll', {})).to.throw(Error, 'Unknown'); +    }) + +    it('throws error on invalid property', () => { +      expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'number' })).to.throw(Error, 'Not number'); +      expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'boolean' })).to.throw(Error, 'Invalid'); +      expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'string' })).to.throw(Error, 'Invalid'); +      expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'number' })).to.throw(Error, 'Invalid'); +    }) +  }); + +  describe('#normalizeUrl', () => { +    const config = { +      default: 'google', +      engines: { +        google: 'https://google.com/search?q={}', +        yahoo: 'https://yahoo.com/search?q={}', +      } +    }; + +    it('convertes search url', () => { +      expect(parsers.normalizeUrl(['google', 'apple'], config)) +        .to.equal('https://google.com/search?q=apple'); +      expect(parsers.normalizeUrl(['yahoo', 'apple'], config)) +        .to.equal('https://yahoo.com/search?q=apple'); +      expect(parsers.normalizeUrl(['google', 'apple', 'banana'], config)) +        .to.equal('https://google.com/search?q=apple%20banana'); +      expect(parsers.normalizeUrl(['yahoo', 'C++CLI'], config)) +        .to.equal('https://yahoo.com/search?q=C%2B%2BCLI'); +    }); + +    it('user default  search engine', () => { +      expect(parsers.normalizeUrl(['apple', 'banana'], config)) +        .to.equal('https://google.com/search?q=apple%20banana'); +    }); +  }); + +  describe('#parseCommandLine', () => { +    it('parse command line as name and args', () => { +      expect(parsers.parseCommandLine('open google apple')).to.deep.equal(['open', ['google', 'apple']]); +      expect(parsers.parseCommandLine('  open  google  apple  ')).to.deep.equal(['open', ['google', 'apple']]); +      expect(parsers.parseCommandLine('')).to.deep.equal(['', []]); +      expect(parsers.parseCommandLine('  ')).to.deep.equal(['', []]); +      expect(parsers.parseCommandLine('exit')).to.deep.equal(['exit', []]); +      expect(parsers.parseCommandLine('  exit  ')).to.deep.equal(['exit', []]); +    }); +  }); +}); diff --git a/test/shared/commands/property.test.js b/test/shared/commands/property.test.js deleted file mode 100644 index d949482..0000000 --- a/test/shared/commands/property.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import { expect } from "chai"; -import { parseProperty } from 'shared/commands/properties'; - -describe("shared/commands/properties", () => { -  describe("#parseProperty", () => { -    it('parse set string', () => { -      let [key, value] = parseProperty('encoding=utf-8', { encoding: 'string' }); -      expect(key).to.equal('encoding'); -      expect(value).to.equal('utf-8'); -    }); - -    it('parse set string', () => { -      let [key, value] = parseProperty('history=50', { history: 'number' }); -      expect(key).to.equal('history'); -      expect(value).to.equal(50); -    }); - -    it('parse set boolean', () => { -      let [key, value] = parseProperty('paste', { paste: 'boolean' }); -      expect(key).to.equal('paste'); -      expect(value).to.be.true; - -      [key, value] = parseProperty('nopaste', { paste: 'boolean' }); -      expect(key).to.equal('paste'); -      expect(value).to.be.false; -    }); - -    it('throws error on unknown property', () => { -      expect(() => parseProperty('charset=utf-8', {})).to.throw(Error, 'Unknown'); -      expect(() => parseProperty('smoothscroll', {})).to.throw(Error, 'Unknown'); -      expect(() => parseProperty('nosmoothscroll', {})).to.throw(Error, 'Unknown'); -    }) - -    it('throws error on invalid property', () => { -      expect(() => parseProperty('charset=utf-8', { charset: 'number' })).to.throw(Error, 'Not number'); -      expect(() => parseProperty('charset=utf-8', { charset: 'boolean' })).to.throw(Error, 'Invalid'); -      expect(() => parseProperty('smoothscroll', { smoothscroll: 'string' })).to.throw(Error, 'Invalid'); -      expect(() => parseProperty('smoothscroll', { smoothscroll: 'number' })).to.throw(Error, 'Invalid'); -    }) -  }); -});  | 
