From c60d0e7392fc708e961614d6b756a045de74f458 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Tue, 30 Apr 2019 14:00:07 +0900
Subject: Rename .js/.jsx to .ts/.tsx

---
 .../controllers/AddonEnabledController.js          |  11 --
 .../controllers/AddonEnabledController.ts          |  11 ++
 src/background/controllers/CommandController.js    |  99 ----------
 src/background/controllers/CommandController.ts    |  99 ++++++++++
 src/background/controllers/FindController.js       |  15 --
 src/background/controllers/FindController.ts       |  15 ++
 src/background/controllers/LinkController.js       |  15 --
 src/background/controllers/LinkController.ts       |  15 ++
 src/background/controllers/MarkController.js       |  15 --
 src/background/controllers/MarkController.ts       |  15 ++
 src/background/controllers/OperationController.js  |  77 --------
 src/background/controllers/OperationController.ts  |  77 ++++++++
 src/background/controllers/SettingController.js    |  18 --
 src/background/controllers/SettingController.ts    |  18 ++
 src/background/controllers/VersionController.js    |  11 --
 src/background/controllers/VersionController.ts    |  11 ++
 src/background/controllers/version.js              |  13 --
 src/background/controllers/version.ts              |  13 ++
 src/background/domains/CommandDocs.js              |  12 --
 src/background/domains/CommandDocs.ts              |  12 ++
 src/background/domains/CompletionGroup.js          |  14 --
 src/background/domains/CompletionGroup.ts          |  14 ++
 src/background/domains/CompletionItem.js           |  24 ---
 src/background/domains/CompletionItem.ts           |  24 +++
 src/background/domains/Completions.js              |  27 ---
 src/background/domains/Completions.ts              |  27 +++
 src/background/domains/GlobalMark.js               |  24 ---
 src/background/domains/GlobalMark.ts               |  24 +++
 src/background/domains/Setting.js                  |  51 -----
 src/background/domains/Setting.ts                  |  51 +++++
 src/background/index.js                            |  23 ---
 src/background/index.ts                            |  23 +++
 src/background/infrastructures/ConsoleClient.js    |  37 ----
 src/background/infrastructures/ConsoleClient.ts    |  37 ++++
 .../infrastructures/ContentMessageClient.js        |  36 ----
 .../infrastructures/ContentMessageClient.ts        |  36 ++++
 .../infrastructures/ContentMessageListener.js      | 135 --------------
 .../infrastructures/ContentMessageListener.ts      | 135 ++++++++++++++
 src/background/infrastructures/MemoryStorage.js    |  19 --
 src/background/infrastructures/MemoryStorage.ts    |  19 ++
 src/background/presenters/IndicatorPresenter.js    |  12 --
 src/background/presenters/IndicatorPresenter.ts    |  12 ++
 src/background/presenters/NotifyPresenter.js       |  23 ---
 src/background/presenters/NotifyPresenter.ts       |  23 +++
 src/background/presenters/TabPresenter.js          | 102 ----------
 src/background/presenters/TabPresenter.ts          | 102 ++++++++++
 src/background/presenters/WindowPresenter.js       |   5 -
 src/background/presenters/WindowPresenter.ts       |   5 +
 src/background/repositories/BookmarkRepository.js  |  13 --
 src/background/repositories/BookmarkRepository.ts  |  13 ++
 .../repositories/BrowserSettingRepository.js       |   8 -
 .../repositories/BrowserSettingRepository.ts       |   8 +
 .../repositories/CompletionsRepository.js          |  31 ----
 .../repositories/CompletionsRepository.ts          |  31 ++++
 src/background/repositories/FindRepository.js      |  19 --
 src/background/repositories/FindRepository.ts      |  19 ++
 src/background/repositories/MarkRepository.js      |  33 ----
 src/background/repositories/MarkRepository.ts      |  33 ++++
 .../repositories/PersistentSettingRepository.js    |  12 --
 .../repositories/PersistentSettingRepository.ts    |  12 ++
 src/background/repositories/SettingRepository.js   |  23 ---
 src/background/repositories/SettingRepository.ts   |  23 +++
 src/background/repositories/VersionRepository.js   |  10 -
 src/background/repositories/VersionRepository.ts   |  10 +
 src/background/usecases/AddonEnabledUseCase.js     |  29 ---
 src/background/usecases/AddonEnabledUseCase.ts     |  29 +++
 src/background/usecases/CommandUseCase.js          | 125 -------------
 src/background/usecases/CommandUseCase.ts          | 125 +++++++++++++
 src/background/usecases/CompletionsUseCase.js      | 205 ---------------------
 src/background/usecases/CompletionsUseCase.ts      | 205 +++++++++++++++++++++
 src/background/usecases/ConsoleUseCase.js          |  61 ------
 src/background/usecases/ConsoleUseCase.ts          |  61 ++++++
 src/background/usecases/FindUseCase.js             |  24 ---
 src/background/usecases/FindUseCase.ts             |  24 +++
 src/background/usecases/LinkUseCase.js             |  19 --
 src/background/usecases/LinkUseCase.ts             |  19 ++
 src/background/usecases/MarkUseCase.js             |  39 ----
 src/background/usecases/MarkUseCase.ts             |  39 ++++
 src/background/usecases/SettingUseCase.js          |  28 ---
 src/background/usecases/SettingUseCase.ts          |  28 +++
 src/background/usecases/TabSelectUseCase.js        |  51 -----
 src/background/usecases/TabSelectUseCase.ts        |  51 +++++
 src/background/usecases/TabUseCase.js              |  77 --------
 src/background/usecases/TabUseCase.ts              |  77 ++++++++
 src/background/usecases/VersionUseCase.js          |  26 ---
 src/background/usecases/VersionUseCase.ts          |  26 +++
 src/background/usecases/ZoomUseCase.js             |  35 ----
 src/background/usecases/ZoomUseCase.ts             |  35 ++++
 src/background/usecases/filters.js                 |  72 --------
 src/background/usecases/filters.ts                 |  72 ++++++++
 src/background/usecases/parsers.js                 |  31 ----
 src/background/usecases/parsers.ts                 |  31 ++++
 92 files changed, 1789 insertions(+), 1789 deletions(-)
 delete mode 100644 src/background/controllers/AddonEnabledController.js
 create mode 100644 src/background/controllers/AddonEnabledController.ts
 delete mode 100644 src/background/controllers/CommandController.js
 create mode 100644 src/background/controllers/CommandController.ts
 delete mode 100644 src/background/controllers/FindController.js
 create mode 100644 src/background/controllers/FindController.ts
 delete mode 100644 src/background/controllers/LinkController.js
 create mode 100644 src/background/controllers/LinkController.ts
 delete mode 100644 src/background/controllers/MarkController.js
 create mode 100644 src/background/controllers/MarkController.ts
 delete mode 100644 src/background/controllers/OperationController.js
 create mode 100644 src/background/controllers/OperationController.ts
 delete mode 100644 src/background/controllers/SettingController.js
 create mode 100644 src/background/controllers/SettingController.ts
 delete mode 100644 src/background/controllers/VersionController.js
 create mode 100644 src/background/controllers/VersionController.ts
 delete mode 100644 src/background/controllers/version.js
 create mode 100644 src/background/controllers/version.ts
 delete mode 100644 src/background/domains/CommandDocs.js
 create mode 100644 src/background/domains/CommandDocs.ts
 delete mode 100644 src/background/domains/CompletionGroup.js
 create mode 100644 src/background/domains/CompletionGroup.ts
 delete mode 100644 src/background/domains/CompletionItem.js
 create mode 100644 src/background/domains/CompletionItem.ts
 delete mode 100644 src/background/domains/Completions.js
 create mode 100644 src/background/domains/Completions.ts
 delete mode 100644 src/background/domains/GlobalMark.js
 create mode 100644 src/background/domains/GlobalMark.ts
 delete mode 100644 src/background/domains/Setting.js
 create mode 100644 src/background/domains/Setting.ts
 delete mode 100644 src/background/index.js
 create mode 100644 src/background/index.ts
 delete mode 100644 src/background/infrastructures/ConsoleClient.js
 create mode 100644 src/background/infrastructures/ConsoleClient.ts
 delete mode 100644 src/background/infrastructures/ContentMessageClient.js
 create mode 100644 src/background/infrastructures/ContentMessageClient.ts
 delete mode 100644 src/background/infrastructures/ContentMessageListener.js
 create mode 100644 src/background/infrastructures/ContentMessageListener.ts
 delete mode 100644 src/background/infrastructures/MemoryStorage.js
 create mode 100644 src/background/infrastructures/MemoryStorage.ts
 delete mode 100644 src/background/presenters/IndicatorPresenter.js
 create mode 100644 src/background/presenters/IndicatorPresenter.ts
 delete mode 100644 src/background/presenters/NotifyPresenter.js
 create mode 100644 src/background/presenters/NotifyPresenter.ts
 delete mode 100644 src/background/presenters/TabPresenter.js
 create mode 100644 src/background/presenters/TabPresenter.ts
 delete mode 100644 src/background/presenters/WindowPresenter.js
 create mode 100644 src/background/presenters/WindowPresenter.ts
 delete mode 100644 src/background/repositories/BookmarkRepository.js
 create mode 100644 src/background/repositories/BookmarkRepository.ts
 delete mode 100644 src/background/repositories/BrowserSettingRepository.js
 create mode 100644 src/background/repositories/BrowserSettingRepository.ts
 delete mode 100644 src/background/repositories/CompletionsRepository.js
 create mode 100644 src/background/repositories/CompletionsRepository.ts
 delete mode 100644 src/background/repositories/FindRepository.js
 create mode 100644 src/background/repositories/FindRepository.ts
 delete mode 100644 src/background/repositories/MarkRepository.js
 create mode 100644 src/background/repositories/MarkRepository.ts
 delete mode 100644 src/background/repositories/PersistentSettingRepository.js
 create mode 100644 src/background/repositories/PersistentSettingRepository.ts
 delete mode 100644 src/background/repositories/SettingRepository.js
 create mode 100644 src/background/repositories/SettingRepository.ts
 delete mode 100644 src/background/repositories/VersionRepository.js
 create mode 100644 src/background/repositories/VersionRepository.ts
 delete mode 100644 src/background/usecases/AddonEnabledUseCase.js
 create mode 100644 src/background/usecases/AddonEnabledUseCase.ts
 delete mode 100644 src/background/usecases/CommandUseCase.js
 create mode 100644 src/background/usecases/CommandUseCase.ts
 delete mode 100644 src/background/usecases/CompletionsUseCase.js
 create mode 100644 src/background/usecases/CompletionsUseCase.ts
 delete mode 100644 src/background/usecases/ConsoleUseCase.js
 create mode 100644 src/background/usecases/ConsoleUseCase.ts
 delete mode 100644 src/background/usecases/FindUseCase.js
 create mode 100644 src/background/usecases/FindUseCase.ts
 delete mode 100644 src/background/usecases/LinkUseCase.js
 create mode 100644 src/background/usecases/LinkUseCase.ts
 delete mode 100644 src/background/usecases/MarkUseCase.js
 create mode 100644 src/background/usecases/MarkUseCase.ts
 delete mode 100644 src/background/usecases/SettingUseCase.js
 create mode 100644 src/background/usecases/SettingUseCase.ts
 delete mode 100644 src/background/usecases/TabSelectUseCase.js
 create mode 100644 src/background/usecases/TabSelectUseCase.ts
 delete mode 100644 src/background/usecases/TabUseCase.js
 create mode 100644 src/background/usecases/TabUseCase.ts
 delete mode 100644 src/background/usecases/VersionUseCase.js
 create mode 100644 src/background/usecases/VersionUseCase.ts
 delete mode 100644 src/background/usecases/ZoomUseCase.js
 create mode 100644 src/background/usecases/ZoomUseCase.ts
 delete mode 100644 src/background/usecases/filters.js
 create mode 100644 src/background/usecases/filters.ts
 delete mode 100644 src/background/usecases/parsers.js
 create mode 100644 src/background/usecases/parsers.ts

(limited to 'src/background')

diff --git a/src/background/controllers/AddonEnabledController.js b/src/background/controllers/AddonEnabledController.js
deleted file mode 100644
index 9a3a521..0000000
--- a/src/background/controllers/AddonEnabledController.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase';
-
-export default class AddonEnabledController {
-  constructor() {
-    this.addonEnabledUseCase = new AddonEnabledUseCase();
-  }
-
-  indicate(enabled) {
-    return this.addonEnabledUseCase.indicate(enabled);
-  }
-}
diff --git a/src/background/controllers/AddonEnabledController.ts b/src/background/controllers/AddonEnabledController.ts
new file mode 100644
index 0000000..9a3a521
--- /dev/null
+++ b/src/background/controllers/AddonEnabledController.ts
@@ -0,0 +1,11 @@
+import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase';
+
+export default class AddonEnabledController {
+  constructor() {
+    this.addonEnabledUseCase = new AddonEnabledUseCase();
+  }
+
+  indicate(enabled) {
+    return this.addonEnabledUseCase.indicate(enabled);
+  }
+}
diff --git a/src/background/controllers/CommandController.js b/src/background/controllers/CommandController.js
deleted file mode 100644
index b113709..0000000
--- a/src/background/controllers/CommandController.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import CompletionsUseCase from '../usecases/CompletionsUseCase';
-import CommandUseCase from '../usecases/CommandUseCase';
-import Completions from '../domains/Completions';
-
-const trimStart = (str) => {
-  // NOTE String.trimStart is available on Firefox 61
-  return str.replace(/^\s+/, '');
-};
-
-export default class CommandController {
-  constructor() {
-    this.completionsUseCase = new CompletionsUseCase();
-    this.commandIndicator = new CommandUseCase();
-  }
-
-  getCompletions(line) {
-    let trimmed = trimStart(line);
-    let words = trimmed.split(/ +/);
-    let name = words[0];
-    if (words.length === 1) {
-      return this.completionsUseCase.queryConsoleCommand(name);
-    }
-    let keywords = trimStart(trimmed.slice(name.length));
-    switch (words[0]) {
-    case 'o':
-    case 'open':
-    case 't':
-    case 'tabopen':
-    case 'w':
-    case 'winopen':
-      return this.completionsUseCase.queryOpen(name, keywords);
-    case 'b':
-    case 'buffer':
-      return this.completionsUseCase.queryBuffer(name, keywords);
-    case 'bd':
-    case 'bdel':
-    case 'bdelete':
-    case 'bdeletes':
-      return this.completionsUseCase.queryBdelete(name, keywords);
-    case 'bd!':
-    case 'bdel!':
-    case 'bdelete!':
-    case 'bdeletes!':
-      return this.completionsUseCase.queryBdeleteForce(name, keywords);
-    case 'set':
-      return this.completionsUseCase.querySet(name, keywords);
-    }
-    return Promise.resolve(Completions.empty());
-  }
-
-  // eslint-disable-next-line complexity
-  exec(line) {
-    let trimmed = trimStart(line);
-    let words = trimmed.split(/ +/);
-    let name = words[0];
-    if (words[0].length === 0) {
-      return Promise.resolve();
-    }
-
-    let keywords = trimStart(trimmed.slice(name.length));
-    switch (words[0]) {
-    case 'o':
-    case 'open':
-      return this.commandIndicator.open(keywords);
-    case 't':
-    case 'tabopen':
-      return this.commandIndicator.tabopen(keywords);
-    case 'w':
-    case 'winopen':
-      return this.commandIndicator.winopen(keywords);
-    case 'b':
-    case 'buffer':
-      return this.commandIndicator.buffer(keywords);
-    case 'bd':
-    case 'bdel':
-    case 'bdelete':
-      return this.commandIndicator.bdelete(false, keywords);
-    case 'bd!':
-    case 'bdel!':
-    case 'bdelete!':
-      return this.commandIndicator.bdelete(true, keywords);
-    case 'bdeletes':
-      return this.commandIndicator.bdeletes(false, keywords);
-    case 'bdeletes!':
-      return this.commandIndicator.bdeletes(true, keywords);
-    case 'addbookmark':
-      return this.commandIndicator.addbookmark(keywords);
-    case 'q':
-    case 'quit':
-      return this.commandIndicator.quit();
-    case 'qa':
-    case 'quitall':
-      return this.commandIndicator.quitAll();
-    case 'set':
-      return this.commandIndicator.set(keywords);
-    }
-    throw new Error(words[0] + ' command is not defined');
-  }
-}
diff --git a/src/background/controllers/CommandController.ts b/src/background/controllers/CommandController.ts
new file mode 100644
index 0000000..b113709
--- /dev/null
+++ b/src/background/controllers/CommandController.ts
@@ -0,0 +1,99 @@
+import CompletionsUseCase from '../usecases/CompletionsUseCase';
+import CommandUseCase from '../usecases/CommandUseCase';
+import Completions from '../domains/Completions';
+
+const trimStart = (str) => {
+  // NOTE String.trimStart is available on Firefox 61
+  return str.replace(/^\s+/, '');
+};
+
+export default class CommandController {
+  constructor() {
+    this.completionsUseCase = new CompletionsUseCase();
+    this.commandIndicator = new CommandUseCase();
+  }
+
+  getCompletions(line) {
+    let trimmed = trimStart(line);
+    let words = trimmed.split(/ +/);
+    let name = words[0];
+    if (words.length === 1) {
+      return this.completionsUseCase.queryConsoleCommand(name);
+    }
+    let keywords = trimStart(trimmed.slice(name.length));
+    switch (words[0]) {
+    case 'o':
+    case 'open':
+    case 't':
+    case 'tabopen':
+    case 'w':
+    case 'winopen':
+      return this.completionsUseCase.queryOpen(name, keywords);
+    case 'b':
+    case 'buffer':
+      return this.completionsUseCase.queryBuffer(name, keywords);
+    case 'bd':
+    case 'bdel':
+    case 'bdelete':
+    case 'bdeletes':
+      return this.completionsUseCase.queryBdelete(name, keywords);
+    case 'bd!':
+    case 'bdel!':
+    case 'bdelete!':
+    case 'bdeletes!':
+      return this.completionsUseCase.queryBdeleteForce(name, keywords);
+    case 'set':
+      return this.completionsUseCase.querySet(name, keywords);
+    }
+    return Promise.resolve(Completions.empty());
+  }
+
+  // eslint-disable-next-line complexity
+  exec(line) {
+    let trimmed = trimStart(line);
+    let words = trimmed.split(/ +/);
+    let name = words[0];
+    if (words[0].length === 0) {
+      return Promise.resolve();
+    }
+
+    let keywords = trimStart(trimmed.slice(name.length));
+    switch (words[0]) {
+    case 'o':
+    case 'open':
+      return this.commandIndicator.open(keywords);
+    case 't':
+    case 'tabopen':
+      return this.commandIndicator.tabopen(keywords);
+    case 'w':
+    case 'winopen':
+      return this.commandIndicator.winopen(keywords);
+    case 'b':
+    case 'buffer':
+      return this.commandIndicator.buffer(keywords);
+    case 'bd':
+    case 'bdel':
+    case 'bdelete':
+      return this.commandIndicator.bdelete(false, keywords);
+    case 'bd!':
+    case 'bdel!':
+    case 'bdelete!':
+      return this.commandIndicator.bdelete(true, keywords);
+    case 'bdeletes':
+      return this.commandIndicator.bdeletes(false, keywords);
+    case 'bdeletes!':
+      return this.commandIndicator.bdeletes(true, keywords);
+    case 'addbookmark':
+      return this.commandIndicator.addbookmark(keywords);
+    case 'q':
+    case 'quit':
+      return this.commandIndicator.quit();
+    case 'qa':
+    case 'quitall':
+      return this.commandIndicator.quitAll();
+    case 'set':
+      return this.commandIndicator.set(keywords);
+    }
+    throw new Error(words[0] + ' command is not defined');
+  }
+}
diff --git a/src/background/controllers/FindController.js b/src/background/controllers/FindController.js
deleted file mode 100644
index caeff98..0000000
--- a/src/background/controllers/FindController.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import FindUseCase from '../usecases/FindUseCase';
-
-export default class FindController {
-  constructor() {
-    this.findUseCase = new FindUseCase();
-  }
-
-  getKeyword() {
-    return this.findUseCase.getKeyword();
-  }
-
-  setKeyword(keyword) {
-    return this.findUseCase.setKeyword(keyword);
-  }
-}
diff --git a/src/background/controllers/FindController.ts b/src/background/controllers/FindController.ts
new file mode 100644
index 0000000..caeff98
--- /dev/null
+++ b/src/background/controllers/FindController.ts
@@ -0,0 +1,15 @@
+import FindUseCase from '../usecases/FindUseCase';
+
+export default class FindController {
+  constructor() {
+    this.findUseCase = new FindUseCase();
+  }
+
+  getKeyword() {
+    return this.findUseCase.getKeyword();
+  }
+
+  setKeyword(keyword) {
+    return this.findUseCase.setKeyword(keyword);
+  }
+}
diff --git a/src/background/controllers/LinkController.js b/src/background/controllers/LinkController.js
deleted file mode 100644
index 7e395b1..0000000
--- a/src/background/controllers/LinkController.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import LinkUseCase from '../usecases/LinkUseCase';
-
-export default class LinkController {
-  constructor() {
-    this.linkUseCase = new LinkUseCase();
-  }
-
-  openToTab(url, tabId) {
-    this.linkUseCase.openToTab(url, tabId);
-  }
-
-  openNewTab(url, openerId, background) {
-    this.linkUseCase.openNewTab(url, openerId, background);
-  }
-}
diff --git a/src/background/controllers/LinkController.ts b/src/background/controllers/LinkController.ts
new file mode 100644
index 0000000..7e395b1
--- /dev/null
+++ b/src/background/controllers/LinkController.ts
@@ -0,0 +1,15 @@
+import LinkUseCase from '../usecases/LinkUseCase';
+
+export default class LinkController {
+  constructor() {
+    this.linkUseCase = new LinkUseCase();
+  }
+
+  openToTab(url, tabId) {
+    this.linkUseCase.openToTab(url, tabId);
+  }
+
+  openNewTab(url, openerId, background) {
+    this.linkUseCase.openNewTab(url, openerId, background);
+  }
+}
diff --git a/src/background/controllers/MarkController.js b/src/background/controllers/MarkController.js
deleted file mode 100644
index 0478369..0000000
--- a/src/background/controllers/MarkController.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import MarkUseCase from '../usecases/MarkUseCase';
-
-export default class MarkController {
-  constructor() {
-    this.markUseCase = new MarkUseCase();
-  }
-
-  setGlobal(key, x, y) {
-    this.markUseCase.setGlobal(key, x, y);
-  }
-
-  jumpGlobal(key) {
-    this.markUseCase.jumpGlobal(key);
-  }
-}
diff --git a/src/background/controllers/MarkController.ts b/src/background/controllers/MarkController.ts
new file mode 100644
index 0000000..0478369
--- /dev/null
+++ b/src/background/controllers/MarkController.ts
@@ -0,0 +1,15 @@
+import MarkUseCase from '../usecases/MarkUseCase';
+
+export default class MarkController {
+  constructor() {
+    this.markUseCase = new MarkUseCase();
+  }
+
+  setGlobal(key, x, y) {
+    this.markUseCase.setGlobal(key, x, y);
+  }
+
+  jumpGlobal(key) {
+    this.markUseCase.jumpGlobal(key);
+  }
+}
diff --git a/src/background/controllers/OperationController.js b/src/background/controllers/OperationController.js
deleted file mode 100644
index 416aa9c..0000000
--- a/src/background/controllers/OperationController.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import operations from '../../shared/operations';
-import FindUseCase from '../usecases/FindUseCase';
-import ConsoleUseCase from '../usecases/ConsoleUseCase';
-import TabUseCase from '../usecases/TabUseCase';
-import TabSelectUseCase from '../usecases/TabSelectUseCase';
-import ZoomUseCase from '../usecases/ZoomUseCase';
-
-export default class OperationController {
-  constructor() {
-    this.findUseCase = new FindUseCase();
-    this.consoleUseCase = new ConsoleUseCase();
-    this.tabUseCase = new TabUseCase();
-    this.tabSelectUseCase = new TabSelectUseCase();
-    this.zoomUseCase = new ZoomUseCase();
-  }
-
-  // eslint-disable-next-line complexity, max-lines-per-function
-  exec(operation) {
-    switch (operation.type) {
-    case operations.TAB_CLOSE:
-      return this.tabUseCase.close(false);
-    case operations.TAB_CLOSE_RIGHT:
-      return this.tabUseCase.closeRight();
-    case operations.TAB_CLOSE_FORCE:
-      return this.tabUseCase.close(true);
-    case operations.TAB_REOPEN:
-      return this.tabUseCase.reopen();
-    case operations.TAB_PREV:
-      return this.tabSelectUseCase.selectPrev(1);
-    case operations.TAB_NEXT:
-      return this.tabSelectUseCase.selectNext(1);
-    case operations.TAB_FIRST:
-      return this.tabSelectUseCase.selectFirst();
-    case operations.TAB_LAST:
-      return this.tabSelectUseCase.selectLast();
-    case operations.TAB_PREV_SEL:
-      return this.tabSelectUseCase.selectPrevSelected();
-    case operations.TAB_RELOAD:
-      return this.tabUseCase.reload(operation.cache);
-    case operations.TAB_PIN:
-      return this.tabUseCase.setPinned(true);
-    case operations.TAB_UNPIN:
-      return this.tabUseCase.setPinned(false);
-    case operations.TAB_TOGGLE_PINNED:
-      return this.tabUseCase.togglePinned();
-    case operations.TAB_DUPLICATE:
-      return this.tabUseCase.duplicate();
-    case operations.PAGE_SOURCE:
-      return this.tabUseCase.openPageSource();
-    case operations.PAGE_HOME:
-      return this.tabUseCase.openHome(operation.newTab);
-    case operations.ZOOM_IN:
-      return this.zoomUseCase.zoomIn();
-    case operations.ZOOM_OUT:
-      return this.zoomUseCase.zoomOut();
-    case operations.ZOOM_NEUTRAL:
-      return this.zoomUseCase.zoomNutoral();
-    case operations.COMMAND_SHOW:
-      return this.consoleUseCase.showCommand();
-    case operations.COMMAND_SHOW_OPEN:
-      return this.consoleUseCase.showOpenCommand(operation.alter);
-    case operations.COMMAND_SHOW_TABOPEN:
-      return this.consoleUseCase.showTabopenCommand(operation.alter);
-    case operations.COMMAND_SHOW_WINOPEN:
-      return this.consoleUseCase.showWinopenCommand(operation.alter);
-    case operations.COMMAND_SHOW_BUFFER:
-      return this.consoleUseCase.showBufferCommand();
-    case operations.COMMAND_SHOW_ADDBOOKMARK:
-      return this.consoleUseCase.showAddbookmarkCommand(operation.alter);
-    case operations.FIND_START:
-      return this.findUseCase.findStart();
-    case operations.CANCEL:
-      return this.consoleUseCase.hideConsole();
-    }
-  }
-}
-
diff --git a/src/background/controllers/OperationController.ts b/src/background/controllers/OperationController.ts
new file mode 100644
index 0000000..416aa9c
--- /dev/null
+++ b/src/background/controllers/OperationController.ts
@@ -0,0 +1,77 @@
+import operations from '../../shared/operations';
+import FindUseCase from '../usecases/FindUseCase';
+import ConsoleUseCase from '../usecases/ConsoleUseCase';
+import TabUseCase from '../usecases/TabUseCase';
+import TabSelectUseCase from '../usecases/TabSelectUseCase';
+import ZoomUseCase from '../usecases/ZoomUseCase';
+
+export default class OperationController {
+  constructor() {
+    this.findUseCase = new FindUseCase();
+    this.consoleUseCase = new ConsoleUseCase();
+    this.tabUseCase = new TabUseCase();
+    this.tabSelectUseCase = new TabSelectUseCase();
+    this.zoomUseCase = new ZoomUseCase();
+  }
+
+  // eslint-disable-next-line complexity, max-lines-per-function
+  exec(operation) {
+    switch (operation.type) {
+    case operations.TAB_CLOSE:
+      return this.tabUseCase.close(false);
+    case operations.TAB_CLOSE_RIGHT:
+      return this.tabUseCase.closeRight();
+    case operations.TAB_CLOSE_FORCE:
+      return this.tabUseCase.close(true);
+    case operations.TAB_REOPEN:
+      return this.tabUseCase.reopen();
+    case operations.TAB_PREV:
+      return this.tabSelectUseCase.selectPrev(1);
+    case operations.TAB_NEXT:
+      return this.tabSelectUseCase.selectNext(1);
+    case operations.TAB_FIRST:
+      return this.tabSelectUseCase.selectFirst();
+    case operations.TAB_LAST:
+      return this.tabSelectUseCase.selectLast();
+    case operations.TAB_PREV_SEL:
+      return this.tabSelectUseCase.selectPrevSelected();
+    case operations.TAB_RELOAD:
+      return this.tabUseCase.reload(operation.cache);
+    case operations.TAB_PIN:
+      return this.tabUseCase.setPinned(true);
+    case operations.TAB_UNPIN:
+      return this.tabUseCase.setPinned(false);
+    case operations.TAB_TOGGLE_PINNED:
+      return this.tabUseCase.togglePinned();
+    case operations.TAB_DUPLICATE:
+      return this.tabUseCase.duplicate();
+    case operations.PAGE_SOURCE:
+      return this.tabUseCase.openPageSource();
+    case operations.PAGE_HOME:
+      return this.tabUseCase.openHome(operation.newTab);
+    case operations.ZOOM_IN:
+      return this.zoomUseCase.zoomIn();
+    case operations.ZOOM_OUT:
+      return this.zoomUseCase.zoomOut();
+    case operations.ZOOM_NEUTRAL:
+      return this.zoomUseCase.zoomNutoral();
+    case operations.COMMAND_SHOW:
+      return this.consoleUseCase.showCommand();
+    case operations.COMMAND_SHOW_OPEN:
+      return this.consoleUseCase.showOpenCommand(operation.alter);
+    case operations.COMMAND_SHOW_TABOPEN:
+      return this.consoleUseCase.showTabopenCommand(operation.alter);
+    case operations.COMMAND_SHOW_WINOPEN:
+      return this.consoleUseCase.showWinopenCommand(operation.alter);
+    case operations.COMMAND_SHOW_BUFFER:
+      return this.consoleUseCase.showBufferCommand();
+    case operations.COMMAND_SHOW_ADDBOOKMARK:
+      return this.consoleUseCase.showAddbookmarkCommand(operation.alter);
+    case operations.FIND_START:
+      return this.findUseCase.findStart();
+    case operations.CANCEL:
+      return this.consoleUseCase.hideConsole();
+    }
+  }
+}
+
diff --git a/src/background/controllers/SettingController.js b/src/background/controllers/SettingController.js
deleted file mode 100644
index e895d72..0000000
--- a/src/background/controllers/SettingController.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import SettingUseCase from '../usecases/SettingUseCase';
-import ContentMessageClient from '../infrastructures/ContentMessageClient';
-
-export default class SettingController {
-  constructor() {
-    this.settingUseCase = new SettingUseCase();
-    this.contentMessageClient = new ContentMessageClient();
-  }
-
-  getSetting() {
-    return this.settingUseCase.get();
-  }
-
-  async reload() {
-    await this.settingUseCase.reload();
-    this.contentMessageClient.broadcastSettingsChanged();
-  }
-}
diff --git a/src/background/controllers/SettingController.ts b/src/background/controllers/SettingController.ts
new file mode 100644
index 0000000..e895d72
--- /dev/null
+++ b/src/background/controllers/SettingController.ts
@@ -0,0 +1,18 @@
+import SettingUseCase from '../usecases/SettingUseCase';
+import ContentMessageClient from '../infrastructures/ContentMessageClient';
+
+export default class SettingController {
+  constructor() {
+    this.settingUseCase = new SettingUseCase();
+    this.contentMessageClient = new ContentMessageClient();
+  }
+
+  getSetting() {
+    return this.settingUseCase.get();
+  }
+
+  async reload() {
+    await this.settingUseCase.reload();
+    this.contentMessageClient.broadcastSettingsChanged();
+  }
+}
diff --git a/src/background/controllers/VersionController.js b/src/background/controllers/VersionController.js
deleted file mode 100644
index c596f9b..0000000
--- a/src/background/controllers/VersionController.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import VersionUseCase from '../usecases/VersionUseCase';
-
-export default class VersionController {
-  constructor() {
-    this.versionUseCase = new VersionUseCase();
-  }
-
-  notify() {
-    this.versionUseCase.notify();
-  }
-}
diff --git a/src/background/controllers/VersionController.ts b/src/background/controllers/VersionController.ts
new file mode 100644
index 0000000..c596f9b
--- /dev/null
+++ b/src/background/controllers/VersionController.ts
@@ -0,0 +1,11 @@
+import VersionUseCase from '../usecases/VersionUseCase';
+
+export default class VersionController {
+  constructor() {
+    this.versionUseCase = new VersionUseCase();
+  }
+
+  notify() {
+    this.versionUseCase.notify();
+  }
+}
diff --git a/src/background/controllers/version.js b/src/background/controllers/version.js
deleted file mode 100644
index ec0f634..0000000
--- a/src/background/controllers/version.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import VersionInteractor from '../usecases/version';
-
-export default class VersionController {
-  constructor() {
-    this.versionInteractor = new VersionInteractor();
-  }
-
-  notifyIfUpdated() {
-    browser.runtime.onInstalled.addListener(() => {
-      return this.versionInteractor.notify();
-    });
-  }
-}
diff --git a/src/background/controllers/version.ts b/src/background/controllers/version.ts
new file mode 100644
index 0000000..ec0f634
--- /dev/null
+++ b/src/background/controllers/version.ts
@@ -0,0 +1,13 @@
+import VersionInteractor from '../usecases/version';
+
+export default class VersionController {
+  constructor() {
+    this.versionInteractor = new VersionInteractor();
+  }
+
+  notifyIfUpdated() {
+    browser.runtime.onInstalled.addListener(() => {
+      return this.versionInteractor.notify();
+    });
+  }
+}
diff --git a/src/background/domains/CommandDocs.js b/src/background/domains/CommandDocs.js
deleted file mode 100644
index 734c68e..0000000
--- a/src/background/domains/CommandDocs.js
+++ /dev/null
@@ -1,12 +0,0 @@
-export default {
-  set: 'Set a value of the property',
-  open: 'Open a URL or search by keywords in current tab',
-  tabopen: 'Open a URL or search by keywords in new tab',
-  winopen: 'Open a URL or search by keywords in new window',
-  buffer: 'Select tabs by matched keywords',
-  bdelete: 'Close a certain tab matched by keywords',
-  bdeletes: 'Close all tabs matched by keywords',
-  quit: 'Close the current tab',
-  quitall: 'Close all tabs',
-};
-
diff --git a/src/background/domains/CommandDocs.ts b/src/background/domains/CommandDocs.ts
new file mode 100644
index 0000000..734c68e
--- /dev/null
+++ b/src/background/domains/CommandDocs.ts
@@ -0,0 +1,12 @@
+export default {
+  set: 'Set a value of the property',
+  open: 'Open a URL or search by keywords in current tab',
+  tabopen: 'Open a URL or search by keywords in new tab',
+  winopen: 'Open a URL or search by keywords in new window',
+  buffer: 'Select tabs by matched keywords',
+  bdelete: 'Close a certain tab matched by keywords',
+  bdeletes: 'Close all tabs matched by keywords',
+  quit: 'Close the current tab',
+  quitall: 'Close all tabs',
+};
+
diff --git a/src/background/domains/CompletionGroup.js b/src/background/domains/CompletionGroup.js
deleted file mode 100644
index 1749d72..0000000
--- a/src/background/domains/CompletionGroup.js
+++ /dev/null
@@ -1,14 +0,0 @@
-export default class CompletionGroup {
-  constructor(name, items) {
-    this.name0 = name;
-    this.items0 = items;
-  }
-
-  get name() {
-    return this.name0;
-  }
-
-  get items() {
-    return this.items0;
-  }
-}
diff --git a/src/background/domains/CompletionGroup.ts b/src/background/domains/CompletionGroup.ts
new file mode 100644
index 0000000..1749d72
--- /dev/null
+++ b/src/background/domains/CompletionGroup.ts
@@ -0,0 +1,14 @@
+export default class CompletionGroup {
+  constructor(name, items) {
+    this.name0 = name;
+    this.items0 = items;
+  }
+
+  get name() {
+    return this.name0;
+  }
+
+  get items() {
+    return this.items0;
+  }
+}
diff --git a/src/background/domains/CompletionItem.js b/src/background/domains/CompletionItem.js
deleted file mode 100644
index c7ad8a1..0000000
--- a/src/background/domains/CompletionItem.js
+++ /dev/null
@@ -1,24 +0,0 @@
-export default class CompletionItem {
-  constructor({ caption, content, url, icon }) {
-    this.caption0 = caption;
-    this.content0 = content;
-    this.url0 = url;
-    this.icon0 = icon;
-  }
-
-  get caption() {
-    return this.caption0;
-  }
-
-  get content() {
-    return this.content0;
-  }
-
-  get url() {
-    return this.url0;
-  }
-
-  get icon() {
-    return this.icon0;
-  }
-}
diff --git a/src/background/domains/CompletionItem.ts b/src/background/domains/CompletionItem.ts
new file mode 100644
index 0000000..c7ad8a1
--- /dev/null
+++ b/src/background/domains/CompletionItem.ts
@@ -0,0 +1,24 @@
+export default class CompletionItem {
+  constructor({ caption, content, url, icon }) {
+    this.caption0 = caption;
+    this.content0 = content;
+    this.url0 = url;
+    this.icon0 = icon;
+  }
+
+  get caption() {
+    return this.caption0;
+  }
+
+  get content() {
+    return this.content0;
+  }
+
+  get url() {
+    return this.url0;
+  }
+
+  get icon() {
+    return this.icon0;
+  }
+}
diff --git a/src/background/domains/Completions.js b/src/background/domains/Completions.js
deleted file mode 100644
index f399743..0000000
--- a/src/background/domains/Completions.js
+++ /dev/null
@@ -1,27 +0,0 @@
-export default class Completions {
-  constructor(groups) {
-    this.g = groups;
-  }
-
-  get groups() {
-    return this.g;
-  }
-
-  serialize() {
-    return this.groups.map(group => ({
-      name: group.name,
-      items: group.items.map(item => ({
-        caption: item.caption,
-        content: item.content,
-        url: item.url,
-        icon: item.icon,
-      })),
-    }));
-  }
-
-  static empty() {
-    return EMPTY_COMPLETIONS;
-  }
-}
-
-let EMPTY_COMPLETIONS = new Completions([]);
diff --git a/src/background/domains/Completions.ts b/src/background/domains/Completions.ts
new file mode 100644
index 0000000..f399743
--- /dev/null
+++ b/src/background/domains/Completions.ts
@@ -0,0 +1,27 @@
+export default class Completions {
+  constructor(groups) {
+    this.g = groups;
+  }
+
+  get groups() {
+    return this.g;
+  }
+
+  serialize() {
+    return this.groups.map(group => ({
+      name: group.name,
+      items: group.items.map(item => ({
+        caption: item.caption,
+        content: item.content,
+        url: item.url,
+        icon: item.icon,
+      })),
+    }));
+  }
+
+  static empty() {
+    return EMPTY_COMPLETIONS;
+  }
+}
+
+let EMPTY_COMPLETIONS = new Completions([]);
diff --git a/src/background/domains/GlobalMark.js b/src/background/domains/GlobalMark.js
deleted file mode 100644
index f0586f1..0000000
--- a/src/background/domains/GlobalMark.js
+++ /dev/null
@@ -1,24 +0,0 @@
-export default class GlobalMark {
-  constructor(tabId, url, x, y) {
-    this.tabId0 = tabId;
-    this.url0 = url;
-    this.x0 = x;
-    this.y0 = y;
-  }
-
-  get tabId() {
-    return this.tabId0;
-  }
-
-  get url() {
-    return this.url0;
-  }
-
-  get x() {
-    return this.x0;
-  }
-
-  get y() {
-    return this.y0;
-  }
-}
diff --git a/src/background/domains/GlobalMark.ts b/src/background/domains/GlobalMark.ts
new file mode 100644
index 0000000..f0586f1
--- /dev/null
+++ b/src/background/domains/GlobalMark.ts
@@ -0,0 +1,24 @@
+export default class GlobalMark {
+  constructor(tabId, url, x, y) {
+    this.tabId0 = tabId;
+    this.url0 = url;
+    this.x0 = x;
+    this.y0 = y;
+  }
+
+  get tabId() {
+    return this.tabId0;
+  }
+
+  get url() {
+    return this.url0;
+  }
+
+  get x() {
+    return this.x0;
+  }
+
+  get y() {
+    return this.y0;
+  }
+}
diff --git a/src/background/domains/Setting.js b/src/background/domains/Setting.js
deleted file mode 100644
index 106ec0f..0000000
--- a/src/background/domains/Setting.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import DefaultSettings from '../../shared/settings/default';
-import * as settingsValues from '../../shared/settings/values';
-
-export default class Setting {
-  constructor({ source, json, form }) {
-    this.obj = {
-      source, json, form
-    };
-  }
-
-  get source() {
-    return this.obj.source;
-  }
-
-  get json() {
-    return this.obj.json;
-  }
-
-  get form() {
-    return this.obj.form;
-  }
-
-  value() {
-    let value = JSON.parse(DefaultSettings.json);
-    if (this.obj.source === 'json') {
-      value = settingsValues.valueFromJson(this.obj.json);
-    } else if (this.obj.source === 'form') {
-      value = settingsValues.valueFromForm(this.obj.form);
-    }
-    if (!value.properties) {
-      value.properties = {};
-    }
-    return { ...settingsValues.valueFromJson(DefaultSettings.json), ...value };
-  }
-
-  serialize() {
-    return this.obj;
-  }
-
-  static deserialize(obj) {
-    return new Setting({ source: obj.source, json: obj.json, form: obj.form });
-  }
-
-  static defaultSettings() {
-    return new Setting({
-      source: DefaultSettings.source,
-      json: DefaultSettings.json,
-      form: {},
-    });
-  }
-}
diff --git a/src/background/domains/Setting.ts b/src/background/domains/Setting.ts
new file mode 100644
index 0000000..106ec0f
--- /dev/null
+++ b/src/background/domains/Setting.ts
@@ -0,0 +1,51 @@
+import DefaultSettings from '../../shared/settings/default';
+import * as settingsValues from '../../shared/settings/values';
+
+export default class Setting {
+  constructor({ source, json, form }) {
+    this.obj = {
+      source, json, form
+    };
+  }
+
+  get source() {
+    return this.obj.source;
+  }
+
+  get json() {
+    return this.obj.json;
+  }
+
+  get form() {
+    return this.obj.form;
+  }
+
+  value() {
+    let value = JSON.parse(DefaultSettings.json);
+    if (this.obj.source === 'json') {
+      value = settingsValues.valueFromJson(this.obj.json);
+    } else if (this.obj.source === 'form') {
+      value = settingsValues.valueFromForm(this.obj.form);
+    }
+    if (!value.properties) {
+      value.properties = {};
+    }
+    return { ...settingsValues.valueFromJson(DefaultSettings.json), ...value };
+  }
+
+  serialize() {
+    return this.obj;
+  }
+
+  static deserialize(obj) {
+    return new Setting({ source: obj.source, json: obj.json, form: obj.form });
+  }
+
+  static defaultSettings() {
+    return new Setting({
+      source: DefaultSettings.source,
+      json: DefaultSettings.json,
+      form: {},
+    });
+  }
+}
diff --git a/src/background/index.js b/src/background/index.js
deleted file mode 100644
index f9efd4d..0000000
--- a/src/background/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import ContentMessageListener from './infrastructures/ContentMessageListener';
-import SettingController from './controllers/SettingController';
-import VersionController from './controllers/VersionController';
-
-let settingController = new SettingController();
-settingController.reload();
-
-browser.runtime.onInstalled.addListener((details) => {
-  if (details.reason !== 'install' && details.reason !== 'update') {
-    return;
-  }
-  new VersionController().notify();
-});
-
-new ContentMessageListener().run();
-browser.storage.onChanged.addListener((changes, area) => {
-  if (area !== 'local') {
-    return;
-  }
-  if (changes.settings) {
-    settingController.reload();
-  }
-});
diff --git a/src/background/index.ts b/src/background/index.ts
new file mode 100644
index 0000000..f9efd4d
--- /dev/null
+++ b/src/background/index.ts
@@ -0,0 +1,23 @@
+import ContentMessageListener from './infrastructures/ContentMessageListener';
+import SettingController from './controllers/SettingController';
+import VersionController from './controllers/VersionController';
+
+let settingController = new SettingController();
+settingController.reload();
+
+browser.runtime.onInstalled.addListener((details) => {
+  if (details.reason !== 'install' && details.reason !== 'update') {
+    return;
+  }
+  new VersionController().notify();
+});
+
+new ContentMessageListener().run();
+browser.storage.onChanged.addListener((changes, area) => {
+  if (area !== 'local') {
+    return;
+  }
+  if (changes.settings) {
+    settingController.reload();
+  }
+});
diff --git a/src/background/infrastructures/ConsoleClient.js b/src/background/infrastructures/ConsoleClient.js
deleted file mode 100644
index f691515..0000000
--- a/src/background/infrastructures/ConsoleClient.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import messages from '../../shared/messages';
-
-export default class ConsoleClient {
-  showCommand(tabId, command) {
-    return browser.tabs.sendMessage(tabId, {
-      type: messages.CONSOLE_SHOW_COMMAND,
-      command,
-    });
-  }
-
-  showFind(tabId) {
-    return browser.tabs.sendMessage(tabId, {
-      type: messages.CONSOLE_SHOW_FIND
-    });
-  }
-
-  showInfo(tabId, message) {
-    return browser.tabs.sendMessage(tabId, {
-      type: messages.CONSOLE_SHOW_INFO,
-      text: message,
-    });
-  }
-
-  showError(tabId, message) {
-    return browser.tabs.sendMessage(tabId, {
-      type: messages.CONSOLE_SHOW_ERROR,
-      text: message,
-    });
-  }
-
-  hide(tabId) {
-    return browser.tabs.sendMessage(tabId, {
-      type: messages.CONSOLE_HIDE,
-    });
-  }
-}
-
diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts
new file mode 100644
index 0000000..f691515
--- /dev/null
+++ b/src/background/infrastructures/ConsoleClient.ts
@@ -0,0 +1,37 @@
+import messages from '../../shared/messages';
+
+export default class ConsoleClient {
+  showCommand(tabId, command) {
+    return browser.tabs.sendMessage(tabId, {
+      type: messages.CONSOLE_SHOW_COMMAND,
+      command,
+    });
+  }
+
+  showFind(tabId) {
+    return browser.tabs.sendMessage(tabId, {
+      type: messages.CONSOLE_SHOW_FIND
+    });
+  }
+
+  showInfo(tabId, message) {
+    return browser.tabs.sendMessage(tabId, {
+      type: messages.CONSOLE_SHOW_INFO,
+      text: message,
+    });
+  }
+
+  showError(tabId, message) {
+    return browser.tabs.sendMessage(tabId, {
+      type: messages.CONSOLE_SHOW_ERROR,
+      text: message,
+    });
+  }
+
+  hide(tabId) {
+    return browser.tabs.sendMessage(tabId, {
+      type: messages.CONSOLE_HIDE,
+    });
+  }
+}
+
diff --git a/src/background/infrastructures/ContentMessageClient.js b/src/background/infrastructures/ContentMessageClient.js
deleted file mode 100644
index 0fab5a3..0000000
--- a/src/background/infrastructures/ContentMessageClient.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import messages from '../../shared/messages';
-
-export default class ContentMessageClient {
-  async broadcastSettingsChanged() {
-    let tabs = await browser.tabs.query({});
-    for (let tab of tabs) {
-      if (tab.url.startsWith('about:')) {
-        continue;
-      }
-      browser.tabs.sendMessage(tab.id, {
-        type: messages.SETTINGS_CHANGED,
-      });
-    }
-  }
-
-  async getAddonEnabled(tabId) {
-    let { enabled } = await browser.tabs.sendMessage(tabId, {
-      type: messages.ADDON_ENABLED_QUERY,
-    });
-    return enabled;
-  }
-
-  toggleAddonEnabled(tabId) {
-    return browser.tabs.sendMessage(tabId, {
-      type: messages.ADDON_TOGGLE_ENABLED,
-    });
-  }
-
-  scrollTo(tabId, x, y) {
-    return browser.tabs.sendMessage(tabId, {
-      type: messages.TAB_SCROLL_TO,
-      x,
-      y,
-    });
-  }
-}
diff --git a/src/background/infrastructures/ContentMessageClient.ts b/src/background/infrastructures/ContentMessageClient.ts
new file mode 100644
index 0000000..0fab5a3
--- /dev/null
+++ b/src/background/infrastructures/ContentMessageClient.ts
@@ -0,0 +1,36 @@
+import messages from '../../shared/messages';
+
+export default class ContentMessageClient {
+  async broadcastSettingsChanged() {
+    let tabs = await browser.tabs.query({});
+    for (let tab of tabs) {
+      if (tab.url.startsWith('about:')) {
+        continue;
+      }
+      browser.tabs.sendMessage(tab.id, {
+        type: messages.SETTINGS_CHANGED,
+      });
+    }
+  }
+
+  async getAddonEnabled(tabId) {
+    let { enabled } = await browser.tabs.sendMessage(tabId, {
+      type: messages.ADDON_ENABLED_QUERY,
+    });
+    return enabled;
+  }
+
+  toggleAddonEnabled(tabId) {
+    return browser.tabs.sendMessage(tabId, {
+      type: messages.ADDON_TOGGLE_ENABLED,
+    });
+  }
+
+  scrollTo(tabId, x, y) {
+    return browser.tabs.sendMessage(tabId, {
+      type: messages.TAB_SCROLL_TO,
+      x,
+      y,
+    });
+  }
+}
diff --git a/src/background/infrastructures/ContentMessageListener.js b/src/background/infrastructures/ContentMessageListener.js
deleted file mode 100644
index 5b0f62e..0000000
--- a/src/background/infrastructures/ContentMessageListener.js
+++ /dev/null
@@ -1,135 +0,0 @@
-import messages from '../../shared/messages';
-import CommandController from '../controllers/CommandController';
-import SettingController from '../controllers/SettingController';
-import FindController from '../controllers/FindController';
-import AddonEnabledController from '../controllers/AddonEnabledController';
-import LinkController from '../controllers/LinkController';
-import OperationController from '../controllers/OperationController';
-import MarkController from '../controllers/MarkController';
-
-export default class ContentMessageListener {
-  constructor() {
-    this.settingController = new SettingController();
-    this.commandController = new CommandController();
-    this.findController = new FindController();
-    this.addonEnabledController = new AddonEnabledController();
-    this.linkController = new LinkController();
-    this.backgroundOperationController = new OperationController();
-    this.markController = new MarkController();
-
-    this.consolePorts = {};
-  }
-
-  run() {
-    browser.runtime.onMessage.addListener((message, sender) => {
-      try {
-        let ret = this.onMessage(message, sender);
-        if (!(ret instanceof Promise)) {
-          return {};
-        }
-        return ret.catch((e) => {
-          return browser.tabs.sendMessage(sender.tab.id, {
-            type: messages.CONSOLE_SHOW_ERROR,
-            text: e.message,
-          });
-        });
-      } catch (e) {
-        return browser.tabs.sendMessage(sender.tab.id, {
-          type: messages.CONSOLE_SHOW_ERROR,
-          text: e.message,
-        });
-      }
-    });
-    browser.runtime.onConnect.addListener(this.onConnected.bind(this));
-  }
-
-  onMessage(message, sender) {
-    switch (message.type) {
-    case messages.CONSOLE_QUERY_COMPLETIONS:
-      return this.onConsoleQueryCompletions(message.text);
-    case messages.CONSOLE_ENTER_COMMAND:
-      return this.onConsoleEnterCommand(message.text);
-    case messages.SETTINGS_QUERY:
-      return this.onSettingsQuery();
-    case messages.FIND_GET_KEYWORD:
-      return this.onFindGetKeyword();
-    case messages.FIND_SET_KEYWORD:
-      return this.onFindSetKeyword(message.keyword);
-    case messages.ADDON_ENABLED_RESPONSE:
-      return this.onAddonEnabledResponse(message.enabled);
-    case messages.OPEN_URL:
-      return this.onOpenUrl(
-        message.newTab, message.url, sender.tab.id, message.background);
-    case messages.BACKGROUND_OPERATION:
-      return this.onBackgroundOperation(message.operation);
-    case messages.MARK_SET_GLOBAL:
-      return this.onMarkSetGlobal(message.key, message.x, message.y);
-    case messages.MARK_JUMP_GLOBAL:
-      return this.onMarkJumpGlobal(message.key);
-    case messages.CONSOLE_FRAME_MESSAGE:
-      return this.onConsoleFrameMessage(sender.tab.id, message.message);
-    }
-  }
-
-  async onConsoleQueryCompletions(line) {
-    let completions = await this.commandController.getCompletions(line);
-    return Promise.resolve(completions.serialize());
-  }
-
-  onConsoleEnterCommand(text) {
-    return this.commandController.exec(text);
-  }
-
-
-  onSettingsQuery() {
-    return this.settingController.getSetting();
-  }
-
-  onFindGetKeyword() {
-    return this.findController.getKeyword();
-  }
-
-  onFindSetKeyword(keyword) {
-    return this.findController.setKeyword(keyword);
-  }
-
-  onAddonEnabledResponse(enabled) {
-    return this.addonEnabledController.indicate(enabled);
-  }
-
-  onOpenUrl(newTab, url, openerId, background) {
-    if (newTab) {
-      return this.linkController.openNewTab(url, openerId, background);
-    }
-    return this.linkController.openToTab(url, openerId);
-  }
-
-  onBackgroundOperation(operation) {
-    return this.backgroundOperationController.exec(operation);
-  }
-
-  onMarkSetGlobal(key, x, y) {
-    return this.markController.setGlobal(key, x, y);
-  }
-
-  onMarkJumpGlobal(key) {
-    return this.markController.jumpGlobal(key);
-  }
-
-  onConsoleFrameMessage(tabId, message) {
-    let port = this.consolePorts[tabId];
-    if (!port) {
-      return;
-    }
-    port.postMessage(message);
-  }
-
-  onConnected(port) {
-    if (port.name !== 'vimvixen-console') {
-      return;
-    }
-
-    let id = port.sender.tab.id;
-    this.consolePorts[id] = port;
-  }
-}
diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts
new file mode 100644
index 0000000..5b0f62e
--- /dev/null
+++ b/src/background/infrastructures/ContentMessageListener.ts
@@ -0,0 +1,135 @@
+import messages from '../../shared/messages';
+import CommandController from '../controllers/CommandController';
+import SettingController from '../controllers/SettingController';
+import FindController from '../controllers/FindController';
+import AddonEnabledController from '../controllers/AddonEnabledController';
+import LinkController from '../controllers/LinkController';
+import OperationController from '../controllers/OperationController';
+import MarkController from '../controllers/MarkController';
+
+export default class ContentMessageListener {
+  constructor() {
+    this.settingController = new SettingController();
+    this.commandController = new CommandController();
+    this.findController = new FindController();
+    this.addonEnabledController = new AddonEnabledController();
+    this.linkController = new LinkController();
+    this.backgroundOperationController = new OperationController();
+    this.markController = new MarkController();
+
+    this.consolePorts = {};
+  }
+
+  run() {
+    browser.runtime.onMessage.addListener((message, sender) => {
+      try {
+        let ret = this.onMessage(message, sender);
+        if (!(ret instanceof Promise)) {
+          return {};
+        }
+        return ret.catch((e) => {
+          return browser.tabs.sendMessage(sender.tab.id, {
+            type: messages.CONSOLE_SHOW_ERROR,
+            text: e.message,
+          });
+        });
+      } catch (e) {
+        return browser.tabs.sendMessage(sender.tab.id, {
+          type: messages.CONSOLE_SHOW_ERROR,
+          text: e.message,
+        });
+      }
+    });
+    browser.runtime.onConnect.addListener(this.onConnected.bind(this));
+  }
+
+  onMessage(message, sender) {
+    switch (message.type) {
+    case messages.CONSOLE_QUERY_COMPLETIONS:
+      return this.onConsoleQueryCompletions(message.text);
+    case messages.CONSOLE_ENTER_COMMAND:
+      return this.onConsoleEnterCommand(message.text);
+    case messages.SETTINGS_QUERY:
+      return this.onSettingsQuery();
+    case messages.FIND_GET_KEYWORD:
+      return this.onFindGetKeyword();
+    case messages.FIND_SET_KEYWORD:
+      return this.onFindSetKeyword(message.keyword);
+    case messages.ADDON_ENABLED_RESPONSE:
+      return this.onAddonEnabledResponse(message.enabled);
+    case messages.OPEN_URL:
+      return this.onOpenUrl(
+        message.newTab, message.url, sender.tab.id, message.background);
+    case messages.BACKGROUND_OPERATION:
+      return this.onBackgroundOperation(message.operation);
+    case messages.MARK_SET_GLOBAL:
+      return this.onMarkSetGlobal(message.key, message.x, message.y);
+    case messages.MARK_JUMP_GLOBAL:
+      return this.onMarkJumpGlobal(message.key);
+    case messages.CONSOLE_FRAME_MESSAGE:
+      return this.onConsoleFrameMessage(sender.tab.id, message.message);
+    }
+  }
+
+  async onConsoleQueryCompletions(line) {
+    let completions = await this.commandController.getCompletions(line);
+    return Promise.resolve(completions.serialize());
+  }
+
+  onConsoleEnterCommand(text) {
+    return this.commandController.exec(text);
+  }
+
+
+  onSettingsQuery() {
+    return this.settingController.getSetting();
+  }
+
+  onFindGetKeyword() {
+    return this.findController.getKeyword();
+  }
+
+  onFindSetKeyword(keyword) {
+    return this.findController.setKeyword(keyword);
+  }
+
+  onAddonEnabledResponse(enabled) {
+    return this.addonEnabledController.indicate(enabled);
+  }
+
+  onOpenUrl(newTab, url, openerId, background) {
+    if (newTab) {
+      return this.linkController.openNewTab(url, openerId, background);
+    }
+    return this.linkController.openToTab(url, openerId);
+  }
+
+  onBackgroundOperation(operation) {
+    return this.backgroundOperationController.exec(operation);
+  }
+
+  onMarkSetGlobal(key, x, y) {
+    return this.markController.setGlobal(key, x, y);
+  }
+
+  onMarkJumpGlobal(key) {
+    return this.markController.jumpGlobal(key);
+  }
+
+  onConsoleFrameMessage(tabId, message) {
+    let port = this.consolePorts[tabId];
+    if (!port) {
+      return;
+    }
+    port.postMessage(message);
+  }
+
+  onConnected(port) {
+    if (port.name !== 'vimvixen-console') {
+      return;
+    }
+
+    let id = port.sender.tab.id;
+    this.consolePorts[id] = port;
+  }
+}
diff --git a/src/background/infrastructures/MemoryStorage.js b/src/background/infrastructures/MemoryStorage.js
deleted file mode 100644
index 3a7e4f2..0000000
--- a/src/background/infrastructures/MemoryStorage.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const db = {};
-
-export default class MemoryStorage {
-  set(name, value) {
-    let data = JSON.stringify(value);
-    if (typeof data === 'undefined') {
-      throw new Error('value is not serializable');
-    }
-    db[name] = data;
-  }
-
-  get(name) {
-    let data = db[name];
-    if (!data) {
-      return undefined;
-    }
-    return JSON.parse(data);
-  }
-}
diff --git a/src/background/infrastructures/MemoryStorage.ts b/src/background/infrastructures/MemoryStorage.ts
new file mode 100644
index 0000000..3a7e4f2
--- /dev/null
+++ b/src/background/infrastructures/MemoryStorage.ts
@@ -0,0 +1,19 @@
+const db = {};
+
+export default class MemoryStorage {
+  set(name, value) {
+    let data = JSON.stringify(value);
+    if (typeof data === 'undefined') {
+      throw new Error('value is not serializable');
+    }
+    db[name] = data;
+  }
+
+  get(name) {
+    let data = db[name];
+    if (!data) {
+      return undefined;
+    }
+    return JSON.parse(data);
+  }
+}
diff --git a/src/background/presenters/IndicatorPresenter.js b/src/background/presenters/IndicatorPresenter.js
deleted file mode 100644
index 5737519..0000000
--- a/src/background/presenters/IndicatorPresenter.js
+++ /dev/null
@@ -1,12 +0,0 @@
-export default class IndicatorPresenter {
-  indicate(enabled) {
-    let path = enabled
-      ? 'resources/enabled_32x32.png'
-      : 'resources/disabled_32x32.png';
-    return browser.browserAction.setIcon({ path });
-  }
-
-  onClick(listener) {
-    browser.browserAction.onClicked.addListener(listener);
-  }
-}
diff --git a/src/background/presenters/IndicatorPresenter.ts b/src/background/presenters/IndicatorPresenter.ts
new file mode 100644
index 0000000..5737519
--- /dev/null
+++ b/src/background/presenters/IndicatorPresenter.ts
@@ -0,0 +1,12 @@
+export default class IndicatorPresenter {
+  indicate(enabled) {
+    let path = enabled
+      ? 'resources/enabled_32x32.png'
+      : 'resources/disabled_32x32.png';
+    return browser.browserAction.setIcon({ path });
+  }
+
+  onClick(listener) {
+    browser.browserAction.onClicked.addListener(listener);
+  }
+}
diff --git a/src/background/presenters/NotifyPresenter.js b/src/background/presenters/NotifyPresenter.js
deleted file mode 100644
index a81f227..0000000
--- a/src/background/presenters/NotifyPresenter.js
+++ /dev/null
@@ -1,23 +0,0 @@
-const NOTIFICATION_ID = 'vimvixen-update';
-
-export default class NotifyPresenter {
-  notify(title, message, onclick) {
-    const listener = (id) => {
-      if (id !== NOTIFICATION_ID) {
-        return;
-      }
-
-      onclick();
-
-      browser.notifications.onClicked.removeListener(listener);
-    };
-    browser.notifications.onClicked.addListener(listener);
-
-    return browser.notifications.create(NOTIFICATION_ID, {
-      'type': 'basic',
-      'iconUrl': browser.extension.getURL('resources/icon_48x48.png'),
-      title,
-      message,
-    });
-  }
-}
diff --git a/src/background/presenters/NotifyPresenter.ts b/src/background/presenters/NotifyPresenter.ts
new file mode 100644
index 0000000..a81f227
--- /dev/null
+++ b/src/background/presenters/NotifyPresenter.ts
@@ -0,0 +1,23 @@
+const NOTIFICATION_ID = 'vimvixen-update';
+
+export default class NotifyPresenter {
+  notify(title, message, onclick) {
+    const listener = (id) => {
+      if (id !== NOTIFICATION_ID) {
+        return;
+      }
+
+      onclick();
+
+      browser.notifications.onClicked.removeListener(listener);
+    };
+    browser.notifications.onClicked.addListener(listener);
+
+    return browser.notifications.create(NOTIFICATION_ID, {
+      'type': 'basic',
+      'iconUrl': browser.extension.getURL('resources/icon_48x48.png'),
+      title,
+      message,
+    });
+  }
+}
diff --git a/src/background/presenters/TabPresenter.js b/src/background/presenters/TabPresenter.js
deleted file mode 100644
index 744be39..0000000
--- a/src/background/presenters/TabPresenter.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import MemoryStorage from '../infrastructures/MemoryStorage';
-
-const CURRENT_SELECTED_KEY = 'tabs.current.selected';
-const LAST_SELECTED_KEY = 'tabs.last.selected';
-
-export default class TabPresenter {
-  open(url, tabId) {
-    return browser.tabs.update(tabId, { url });
-  }
-
-  create(url, opts) {
-    return browser.tabs.create({ url, ...opts });
-  }
-
-  async getCurrent() {
-    let tabs = await browser.tabs.query({
-      active: true, currentWindow: true
-    });
-    return tabs[0];
-  }
-
-  getAll() {
-    return browser.tabs.query({ currentWindow: true });
-  }
-
-  async getLastSelectedId() {
-    let cache = new MemoryStorage();
-    let tabId = await cache.get(LAST_SELECTED_KEY);
-    if (tabId === null || typeof tabId === 'undefined') {
-      return;
-    }
-    return tabId;
-  }
-
-  async getByKeyword(keyword, excludePinned = false) {
-    let tabs = await browser.tabs.query({ currentWindow: true });
-    return tabs.filter((t) => {
-      return t.url.toLowerCase().includes(keyword.toLowerCase()) ||
-        t.title && t.title.toLowerCase().includes(keyword.toLowerCase());
-    }).filter((t) => {
-      return !(excludePinned && t.pinned);
-    });
-  }
-
-  select(tabId) {
-    return browser.tabs.update(tabId, { active: true });
-  }
-
-  remove(ids) {
-    return browser.tabs.remove(ids);
-  }
-
-  async reopen() {
-    let window = await browser.windows.getCurrent();
-    let sessions = await browser.sessions.getRecentlyClosed();
-    let session = sessions.find((s) => {
-      return s.tab && s.tab.windowId === window.id;
-    });
-    if (!session) {
-      return;
-    }
-    if (session.tab) {
-      return browser.sessions.restore(session.tab.sessionId);
-    }
-    return browser.sessions.restore(session.window.sessionId);
-  }
-
-  reload(tabId, cache) {
-    return browser.tabs.reload(tabId, { bypassCache: cache });
-  }
-
-  setPinned(tabId, pinned) {
-    return browser.tabs.update(tabId, { pinned });
-  }
-
-  duplicate(id) {
-    return browser.tabs.duplicate(id);
-  }
-
-  getZoom(tabId) {
-    return browser.tabs.getZoom(tabId);
-  }
-
-  setZoom(tabId, factor) {
-    return browser.tabs.setZoom(tabId, factor);
-  }
-
-  onSelected(listener) {
-    browser.tabs.onActivated.addListener(listener);
-  }
-}
-
-let tabPresenter = new TabPresenter();
-tabPresenter.onSelected((tab) => {
-  let cache = new MemoryStorage();
-
-  let lastId = cache.get(CURRENT_SELECTED_KEY);
-  if (lastId) {
-    cache.set(LAST_SELECTED_KEY, lastId);
-  }
-  cache.set(CURRENT_SELECTED_KEY, tab.tabId);
-});
diff --git a/src/background/presenters/TabPresenter.ts b/src/background/presenters/TabPresenter.ts
new file mode 100644
index 0000000..744be39
--- /dev/null
+++ b/src/background/presenters/TabPresenter.ts
@@ -0,0 +1,102 @@
+import MemoryStorage from '../infrastructures/MemoryStorage';
+
+const CURRENT_SELECTED_KEY = 'tabs.current.selected';
+const LAST_SELECTED_KEY = 'tabs.last.selected';
+
+export default class TabPresenter {
+  open(url, tabId) {
+    return browser.tabs.update(tabId, { url });
+  }
+
+  create(url, opts) {
+    return browser.tabs.create({ url, ...opts });
+  }
+
+  async getCurrent() {
+    let tabs = await browser.tabs.query({
+      active: true, currentWindow: true
+    });
+    return tabs[0];
+  }
+
+  getAll() {
+    return browser.tabs.query({ currentWindow: true });
+  }
+
+  async getLastSelectedId() {
+    let cache = new MemoryStorage();
+    let tabId = await cache.get(LAST_SELECTED_KEY);
+    if (tabId === null || typeof tabId === 'undefined') {
+      return;
+    }
+    return tabId;
+  }
+
+  async getByKeyword(keyword, excludePinned = false) {
+    let tabs = await browser.tabs.query({ currentWindow: true });
+    return tabs.filter((t) => {
+      return t.url.toLowerCase().includes(keyword.toLowerCase()) ||
+        t.title && t.title.toLowerCase().includes(keyword.toLowerCase());
+    }).filter((t) => {
+      return !(excludePinned && t.pinned);
+    });
+  }
+
+  select(tabId) {
+    return browser.tabs.update(tabId, { active: true });
+  }
+
+  remove(ids) {
+    return browser.tabs.remove(ids);
+  }
+
+  async reopen() {
+    let window = await browser.windows.getCurrent();
+    let sessions = await browser.sessions.getRecentlyClosed();
+    let session = sessions.find((s) => {
+      return s.tab && s.tab.windowId === window.id;
+    });
+    if (!session) {
+      return;
+    }
+    if (session.tab) {
+      return browser.sessions.restore(session.tab.sessionId);
+    }
+    return browser.sessions.restore(session.window.sessionId);
+  }
+
+  reload(tabId, cache) {
+    return browser.tabs.reload(tabId, { bypassCache: cache });
+  }
+
+  setPinned(tabId, pinned) {
+    return browser.tabs.update(tabId, { pinned });
+  }
+
+  duplicate(id) {
+    return browser.tabs.duplicate(id);
+  }
+
+  getZoom(tabId) {
+    return browser.tabs.getZoom(tabId);
+  }
+
+  setZoom(tabId, factor) {
+    return browser.tabs.setZoom(tabId, factor);
+  }
+
+  onSelected(listener) {
+    browser.tabs.onActivated.addListener(listener);
+  }
+}
+
+let tabPresenter = new TabPresenter();
+tabPresenter.onSelected((tab) => {
+  let cache = new MemoryStorage();
+
+  let lastId = cache.get(CURRENT_SELECTED_KEY);
+  if (lastId) {
+    cache.set(LAST_SELECTED_KEY, lastId);
+  }
+  cache.set(CURRENT_SELECTED_KEY, tab.tabId);
+});
diff --git a/src/background/presenters/WindowPresenter.js b/src/background/presenters/WindowPresenter.js
deleted file mode 100644
index a82c4a2..0000000
--- a/src/background/presenters/WindowPresenter.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export default class WindowPresenter {
-  create(url) {
-    return browser.windows.create({ url });
-  }
-}
diff --git a/src/background/presenters/WindowPresenter.ts b/src/background/presenters/WindowPresenter.ts
new file mode 100644
index 0000000..a82c4a2
--- /dev/null
+++ b/src/background/presenters/WindowPresenter.ts
@@ -0,0 +1,5 @@
+export default class WindowPresenter {
+  create(url) {
+    return browser.windows.create({ url });
+  }
+}
diff --git a/src/background/repositories/BookmarkRepository.js b/src/background/repositories/BookmarkRepository.js
deleted file mode 100644
index 99f7ec4..0000000
--- a/src/background/repositories/BookmarkRepository.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export default class BookmarkRepository {
-  async create(title, url) {
-    let item = await browser.bookmarks.create({
-      type: 'bookmark',
-      title,
-      url,
-    });
-    if (!item) {
-      throw new Error('Could not create a bookmark');
-    }
-    return item;
-  }
-}
diff --git a/src/background/repositories/BookmarkRepository.ts b/src/background/repositories/BookmarkRepository.ts
new file mode 100644
index 0000000..99f7ec4
--- /dev/null
+++ b/src/background/repositories/BookmarkRepository.ts
@@ -0,0 +1,13 @@
+export default class BookmarkRepository {
+  async create(title, url) {
+    let item = await browser.bookmarks.create({
+      type: 'bookmark',
+      title,
+      url,
+    });
+    if (!item) {
+      throw new Error('Could not create a bookmark');
+    }
+    return item;
+  }
+}
diff --git a/src/background/repositories/BrowserSettingRepository.js b/src/background/repositories/BrowserSettingRepository.js
deleted file mode 100644
index a9d2c06..0000000
--- a/src/background/repositories/BrowserSettingRepository.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as urls from '../../shared/urls';
-
-export default class BrowserSettingRepository {
-  async getHomepageUrls() {
-    let { value } = await browser.browserSettings.homepageOverride.get({});
-    return value.split('|').map(urls.normalizeUrl);
-  }
-}
diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts
new file mode 100644
index 0000000..a9d2c06
--- /dev/null
+++ b/src/background/repositories/BrowserSettingRepository.ts
@@ -0,0 +1,8 @@
+import * as urls from '../../shared/urls';
+
+export default class BrowserSettingRepository {
+  async getHomepageUrls() {
+    let { value } = await browser.browserSettings.homepageOverride.get({});
+    return value.split('|').map(urls.normalizeUrl);
+  }
+}
diff --git a/src/background/repositories/CompletionsRepository.js b/src/background/repositories/CompletionsRepository.js
deleted file mode 100644
index 1318d36..0000000
--- a/src/background/repositories/CompletionsRepository.js
+++ /dev/null
@@ -1,31 +0,0 @@
-export default class CompletionsRepository {
-  async queryBookmarks(keywords) {
-    let items = await browser.bookmarks.search({ query: keywords });
-    return items.filter((item) => {
-      let url = undefined;
-      try {
-        url = new URL(item.url);
-      } catch (e) {
-        return false;
-      }
-      return item.type === 'bookmark' && url.protocol !== 'place:';
-    });
-  }
-
-  queryHistories(keywords) {
-    return browser.history.search({
-      text: keywords,
-      startTime: 0,
-    });
-  }
-
-  async queryTabs(keywords, excludePinned) {
-    let tabs = await browser.tabs.query({ currentWindow: true });
-    return tabs.filter((t) => {
-      return t.url.toLowerCase().includes(keywords.toLowerCase()) ||
-        t.title && t.title.toLowerCase().includes(keywords.toLowerCase());
-    }).filter((t) => {
-      return !(excludePinned && t.pinned);
-    });
-  }
-}
diff --git a/src/background/repositories/CompletionsRepository.ts b/src/background/repositories/CompletionsRepository.ts
new file mode 100644
index 0000000..1318d36
--- /dev/null
+++ b/src/background/repositories/CompletionsRepository.ts
@@ -0,0 +1,31 @@
+export default class CompletionsRepository {
+  async queryBookmarks(keywords) {
+    let items = await browser.bookmarks.search({ query: keywords });
+    return items.filter((item) => {
+      let url = undefined;
+      try {
+        url = new URL(item.url);
+      } catch (e) {
+        return false;
+      }
+      return item.type === 'bookmark' && url.protocol !== 'place:';
+    });
+  }
+
+  queryHistories(keywords) {
+    return browser.history.search({
+      text: keywords,
+      startTime: 0,
+    });
+  }
+
+  async queryTabs(keywords, excludePinned) {
+    let tabs = await browser.tabs.query({ currentWindow: true });
+    return tabs.filter((t) => {
+      return t.url.toLowerCase().includes(keywords.toLowerCase()) ||
+        t.title && t.title.toLowerCase().includes(keywords.toLowerCase());
+    }).filter((t) => {
+      return !(excludePinned && t.pinned);
+    });
+  }
+}
diff --git a/src/background/repositories/FindRepository.js b/src/background/repositories/FindRepository.js
deleted file mode 100644
index 74ec914..0000000
--- a/src/background/repositories/FindRepository.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import MemoryStorage from '../infrastructures/MemoryStorage';
-
-const FIND_KEYWORD_KEY = 'find-keyword';
-
-export default class FindRepository {
-  constructor() {
-    this.cache = new MemoryStorage();
-  }
-
-  getKeyword() {
-    return Promise.resolve(this.cache.get(FIND_KEYWORD_KEY));
-  }
-
-  setKeyword(keyword) {
-    this.cache.set(FIND_KEYWORD_KEY, keyword);
-    return Promise.resolve();
-  }
-}
-
diff --git a/src/background/repositories/FindRepository.ts b/src/background/repositories/FindRepository.ts
new file mode 100644
index 0000000..74ec914
--- /dev/null
+++ b/src/background/repositories/FindRepository.ts
@@ -0,0 +1,19 @@
+import MemoryStorage from '../infrastructures/MemoryStorage';
+
+const FIND_KEYWORD_KEY = 'find-keyword';
+
+export default class FindRepository {
+  constructor() {
+    this.cache = new MemoryStorage();
+  }
+
+  getKeyword() {
+    return Promise.resolve(this.cache.get(FIND_KEYWORD_KEY));
+  }
+
+  setKeyword(keyword) {
+    this.cache.set(FIND_KEYWORD_KEY, keyword);
+    return Promise.resolve();
+  }
+}
+
diff --git a/src/background/repositories/MarkRepository.js b/src/background/repositories/MarkRepository.js
deleted file mode 100644
index 282c712..0000000
--- a/src/background/repositories/MarkRepository.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import MemoryStorage from '../infrastructures/MemoryStorage';
-import GlobalMark from '../domains/GlobalMark';
-
-const MARK_KEY = 'mark';
-
-export default class MarkRepository {
-  constructor() {
-    this.cache = new MemoryStorage();
-  }
-
-  getMark(key) {
-    let marks = this.getOrEmptyMarks();
-    let data = marks[key];
-    if (!data) {
-      return Promise.resolve(undefined);
-    }
-    let mark = new GlobalMark(data.tabId, data.url, data.x, data.y);
-    return Promise.resolve(mark);
-  }
-
-  setMark(key, mark) {
-    let marks = this.getOrEmptyMarks();
-    marks[key] = { tabId: mark.tabId, url: mark.url, x: mark.x, y: mark.y };
-    this.cache.set(MARK_KEY, marks);
-
-    return Promise.resolve();
-  }
-
-  getOrEmptyMarks() {
-    return this.cache.get(MARK_KEY) || {};
-  }
-}
-
diff --git a/src/background/repositories/MarkRepository.ts b/src/background/repositories/MarkRepository.ts
new file mode 100644
index 0000000..282c712
--- /dev/null
+++ b/src/background/repositories/MarkRepository.ts
@@ -0,0 +1,33 @@
+import MemoryStorage from '../infrastructures/MemoryStorage';
+import GlobalMark from '../domains/GlobalMark';
+
+const MARK_KEY = 'mark';
+
+export default class MarkRepository {
+  constructor() {
+    this.cache = new MemoryStorage();
+  }
+
+  getMark(key) {
+    let marks = this.getOrEmptyMarks();
+    let data = marks[key];
+    if (!data) {
+      return Promise.resolve(undefined);
+    }
+    let mark = new GlobalMark(data.tabId, data.url, data.x, data.y);
+    return Promise.resolve(mark);
+  }
+
+  setMark(key, mark) {
+    let marks = this.getOrEmptyMarks();
+    marks[key] = { tabId: mark.tabId, url: mark.url, x: mark.x, y: mark.y };
+    this.cache.set(MARK_KEY, marks);
+
+    return Promise.resolve();
+  }
+
+  getOrEmptyMarks() {
+    return this.cache.get(MARK_KEY) || {};
+  }
+}
+
diff --git a/src/background/repositories/PersistentSettingRepository.js b/src/background/repositories/PersistentSettingRepository.js
deleted file mode 100644
index 4cab107..0000000
--- a/src/background/repositories/PersistentSettingRepository.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Setting from '../domains/Setting';
-
-export default class SettingRepository {
-  async load() {
-    let { settings } = await browser.storage.local.get('settings');
-    if (!settings) {
-      return null;
-    }
-    return Setting.deserialize(settings);
-  }
-}
-
diff --git a/src/background/repositories/PersistentSettingRepository.ts b/src/background/repositories/PersistentSettingRepository.ts
new file mode 100644
index 0000000..4cab107
--- /dev/null
+++ b/src/background/repositories/PersistentSettingRepository.ts
@@ -0,0 +1,12 @@
+import Setting from '../domains/Setting';
+
+export default class SettingRepository {
+  async load() {
+    let { settings } = await browser.storage.local.get('settings');
+    if (!settings) {
+      return null;
+    }
+    return Setting.deserialize(settings);
+  }
+}
+
diff --git a/src/background/repositories/SettingRepository.js b/src/background/repositories/SettingRepository.js
deleted file mode 100644
index c4667a9..0000000
--- a/src/background/repositories/SettingRepository.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import MemoryStorage from '../infrastructures/MemoryStorage';
-
-const CACHED_SETTING_KEY = 'setting';
-
-export default class SettingRepository {
-  constructor() {
-    this.cache = new MemoryStorage();
-  }
-
-  get() {
-    return Promise.resolve(this.cache.get(CACHED_SETTING_KEY));
-  }
-
-  update(value) {
-    return this.cache.set(CACHED_SETTING_KEY, value);
-  }
-
-  async setProperty(name, value) {
-    let current = await this.get();
-    current.properties[name] = value;
-    return this.update(current);
-  }
-}
diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts
new file mode 100644
index 0000000..c4667a9
--- /dev/null
+++ b/src/background/repositories/SettingRepository.ts
@@ -0,0 +1,23 @@
+import MemoryStorage from '../infrastructures/MemoryStorage';
+
+const CACHED_SETTING_KEY = 'setting';
+
+export default class SettingRepository {
+  constructor() {
+    this.cache = new MemoryStorage();
+  }
+
+  get() {
+    return Promise.resolve(this.cache.get(CACHED_SETTING_KEY));
+  }
+
+  update(value) {
+    return this.cache.set(CACHED_SETTING_KEY, value);
+  }
+
+  async setProperty(name, value) {
+    let current = await this.get();
+    current.properties[name] = value;
+    return this.update(current);
+  }
+}
diff --git a/src/background/repositories/VersionRepository.js b/src/background/repositories/VersionRepository.js
deleted file mode 100644
index 4c71d05..0000000
--- a/src/background/repositories/VersionRepository.js
+++ /dev/null
@@ -1,10 +0,0 @@
-export default class VersionRepository {
-  async get() {
-    let { version } = await browser.storage.local.get('version');
-    return version;
-  }
-
-  update(version) {
-    return browser.storage.local.set({ version });
-  }
-}
diff --git a/src/background/repositories/VersionRepository.ts b/src/background/repositories/VersionRepository.ts
new file mode 100644
index 0000000..4c71d05
--- /dev/null
+++ b/src/background/repositories/VersionRepository.ts
@@ -0,0 +1,10 @@
+export default class VersionRepository {
+  async get() {
+    let { version } = await browser.storage.local.get('version');
+    return version;
+  }
+
+  update(version) {
+    return browser.storage.local.set({ version });
+  }
+}
diff --git a/src/background/usecases/AddonEnabledUseCase.js b/src/background/usecases/AddonEnabledUseCase.js
deleted file mode 100644
index bb2c347..0000000
--- a/src/background/usecases/AddonEnabledUseCase.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import IndicatorPresenter from '../presenters/IndicatorPresenter';
-import TabPresenter from '../presenters/TabPresenter';
-import ContentMessageClient from '../infrastructures/ContentMessageClient';
-
-export default class AddonEnabledUseCase {
-  constructor() {
-    this.indicatorPresentor = new IndicatorPresenter();
-
-    this.indicatorPresentor.onClick(tab => this.onIndicatorClick(tab.id));
-
-    this.tabPresenter = new TabPresenter();
-    this.tabPresenter.onSelected(info => this.onTabSelected(info.tabId));
-
-    this.contentMessageClient = new ContentMessageClient();
-  }
-
-  indicate(enabled) {
-    return this.indicatorPresentor.indicate(enabled);
-  }
-
-  onIndicatorClick(tabId) {
-    return this.contentMessageClient.toggleAddonEnabled(tabId);
-  }
-
-  async onTabSelected(tabId) {
-    let enabled = await this.contentMessageClient.getAddonEnabled(tabId);
-    return this.indicatorPresentor.indicate(enabled);
-  }
-}
diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts
new file mode 100644
index 0000000..bb2c347
--- /dev/null
+++ b/src/background/usecases/AddonEnabledUseCase.ts
@@ -0,0 +1,29 @@
+import IndicatorPresenter from '../presenters/IndicatorPresenter';
+import TabPresenter from '../presenters/TabPresenter';
+import ContentMessageClient from '../infrastructures/ContentMessageClient';
+
+export default class AddonEnabledUseCase {
+  constructor() {
+    this.indicatorPresentor = new IndicatorPresenter();
+
+    this.indicatorPresentor.onClick(tab => this.onIndicatorClick(tab.id));
+
+    this.tabPresenter = new TabPresenter();
+    this.tabPresenter.onSelected(info => this.onTabSelected(info.tabId));
+
+    this.contentMessageClient = new ContentMessageClient();
+  }
+
+  indicate(enabled) {
+    return this.indicatorPresentor.indicate(enabled);
+  }
+
+  onIndicatorClick(tabId) {
+    return this.contentMessageClient.toggleAddonEnabled(tabId);
+  }
+
+  async onTabSelected(tabId) {
+    let enabled = await this.contentMessageClient.getAddonEnabled(tabId);
+    return this.indicatorPresentor.indicate(enabled);
+  }
+}
diff --git a/src/background/usecases/CommandUseCase.js b/src/background/usecases/CommandUseCase.js
deleted file mode 100644
index 9ec46fe..0000000
--- a/src/background/usecases/CommandUseCase.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import * as parsers from './parsers';
-import * as urls from '../../shared/urls';
-import TabPresenter from '../presenters/TabPresenter';
-import WindowPresenter from '../presenters/WindowPresenter';
-import SettingRepository from '../repositories/SettingRepository';
-import BookmarkRepository from '../repositories/BookmarkRepository';
-import ConsoleClient from '../infrastructures/ConsoleClient';
-import ContentMessageClient from '../infrastructures/ContentMessageClient';
-import * as properties from 'shared/settings/properties';
-
-export default class CommandIndicator {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-    this.windowPresenter = new WindowPresenter();
-    this.settingRepository = new SettingRepository();
-    this.bookmarkRepository = new BookmarkRepository();
-    this.consoleClient = new ConsoleClient();
-
-    this.contentMessageClient = new ContentMessageClient();
-  }
-
-  async open(keywords) {
-    let url = await this.urlOrSearch(keywords);
-    return this.tabPresenter.open(url);
-  }
-
-  async tabopen(keywords) {
-    let url = await this.urlOrSearch(keywords);
-    return this.tabPresenter.create(url);
-  }
-
-  async winopen(keywords) {
-    let url = await this.urlOrSearch(keywords);
-    return this.windowPresenter.create(url);
-  }
-
-  // eslint-disable-next-line max-statements
-  async buffer(keywords) {
-    if (keywords.length === 0) {
-      return;
-    }
-
-    if (!isNaN(keywords)) {
-      let tabs = await this.tabPresenter.getAll();
-      let index = parseInt(keywords, 10) - 1;
-      if (index < 0 || tabs.length <= index) {
-        throw new RangeError(`tab ${index + 1} does not exist`);
-      }
-      return this.tabPresenter.select(tabs[index].id);
-    } else if (keywords.trim() === '%') {
-      // Select current window
-      return;
-    } else if (keywords.trim() === '#') {
-      // Select last selected window
-      let lastId = await this.tabPresenter.getLastSelectedId();
-      if (typeof lastId === 'undefined' || lastId === null) {
-        throw new Error('No last selected tab');
-      }
-      return this.tabPresenter.select(lastId);
-    }
-
-    let current = await this.tabPresenter.getCurrent();
-    let tabs = await this.tabPresenter.getByKeyword(keywords);
-    if (tabs.length === 0) {
-      throw new RangeError('No matching buffer for ' + keywords);
-    }
-    for (let tab of tabs) {
-      if (tab.index > current.index) {
-        return this.tabPresenter.select(tab.id);
-      }
-    }
-    return this.tabPresenter.select(tabs[0].id);
-  }
-
-  async bdelete(force, keywords) {
-    let excludePinned = !force;
-    let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned);
-    if (tabs.length === 0) {
-      throw new Error('No matching buffer for ' + keywords);
-    } else if (tabs.length > 1) {
-      throw new Error('More than one match for ' + keywords);
-    }
-    return this.tabPresenter.remove([tabs[0].id]);
-  }
-
-  async bdeletes(force, keywords) {
-    let excludePinned = !force;
-    let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned);
-    let ids = tabs.map(tab => tab.id);
-    return this.tabPresenter.remove(ids);
-  }
-
-  async quit() {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.remove([tab.id]);
-  }
-
-  async quitAll() {
-    let tabs = await this.tabPresenter.getAll();
-    let ids = tabs.map(tab => tab.id);
-    this.tabPresenter.remove(ids);
-  }
-
-  async addbookmark(title) {
-    let tab = await this.tabPresenter.getCurrent();
-    let item = await this.bookmarkRepository.create(title, tab.url);
-    let message = 'Saved current page: ' + item.url;
-    return this.consoleClient.showInfo(tab.id, message);
-  }
-
-  async set(keywords) {
-    if (keywords.length === 0) {
-      return;
-    }
-    let [name, value] = parsers.parseSetOption(keywords, properties.types);
-    await this.settingRepository.setProperty(name, value);
-
-    return this.contentMessageClient.broadcastSettingsChanged();
-  }
-
-  async urlOrSearch(keywords) {
-    let settings = await this.settingRepository.get();
-    return urls.searchUrl(keywords, settings.search);
-  }
-}
diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts
new file mode 100644
index 0000000..9ec46fe
--- /dev/null
+++ b/src/background/usecases/CommandUseCase.ts
@@ -0,0 +1,125 @@
+import * as parsers from './parsers';
+import * as urls from '../../shared/urls';
+import TabPresenter from '../presenters/TabPresenter';
+import WindowPresenter from '../presenters/WindowPresenter';
+import SettingRepository from '../repositories/SettingRepository';
+import BookmarkRepository from '../repositories/BookmarkRepository';
+import ConsoleClient from '../infrastructures/ConsoleClient';
+import ContentMessageClient from '../infrastructures/ContentMessageClient';
+import * as properties from 'shared/settings/properties';
+
+export default class CommandIndicator {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+    this.windowPresenter = new WindowPresenter();
+    this.settingRepository = new SettingRepository();
+    this.bookmarkRepository = new BookmarkRepository();
+    this.consoleClient = new ConsoleClient();
+
+    this.contentMessageClient = new ContentMessageClient();
+  }
+
+  async open(keywords) {
+    let url = await this.urlOrSearch(keywords);
+    return this.tabPresenter.open(url);
+  }
+
+  async tabopen(keywords) {
+    let url = await this.urlOrSearch(keywords);
+    return this.tabPresenter.create(url);
+  }
+
+  async winopen(keywords) {
+    let url = await this.urlOrSearch(keywords);
+    return this.windowPresenter.create(url);
+  }
+
+  // eslint-disable-next-line max-statements
+  async buffer(keywords) {
+    if (keywords.length === 0) {
+      return;
+    }
+
+    if (!isNaN(keywords)) {
+      let tabs = await this.tabPresenter.getAll();
+      let index = parseInt(keywords, 10) - 1;
+      if (index < 0 || tabs.length <= index) {
+        throw new RangeError(`tab ${index + 1} does not exist`);
+      }
+      return this.tabPresenter.select(tabs[index].id);
+    } else if (keywords.trim() === '%') {
+      // Select current window
+      return;
+    } else if (keywords.trim() === '#') {
+      // Select last selected window
+      let lastId = await this.tabPresenter.getLastSelectedId();
+      if (typeof lastId === 'undefined' || lastId === null) {
+        throw new Error('No last selected tab');
+      }
+      return this.tabPresenter.select(lastId);
+    }
+
+    let current = await this.tabPresenter.getCurrent();
+    let tabs = await this.tabPresenter.getByKeyword(keywords);
+    if (tabs.length === 0) {
+      throw new RangeError('No matching buffer for ' + keywords);
+    }
+    for (let tab of tabs) {
+      if (tab.index > current.index) {
+        return this.tabPresenter.select(tab.id);
+      }
+    }
+    return this.tabPresenter.select(tabs[0].id);
+  }
+
+  async bdelete(force, keywords) {
+    let excludePinned = !force;
+    let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned);
+    if (tabs.length === 0) {
+      throw new Error('No matching buffer for ' + keywords);
+    } else if (tabs.length > 1) {
+      throw new Error('More than one match for ' + keywords);
+    }
+    return this.tabPresenter.remove([tabs[0].id]);
+  }
+
+  async bdeletes(force, keywords) {
+    let excludePinned = !force;
+    let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned);
+    let ids = tabs.map(tab => tab.id);
+    return this.tabPresenter.remove(ids);
+  }
+
+  async quit() {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.tabPresenter.remove([tab.id]);
+  }
+
+  async quitAll() {
+    let tabs = await this.tabPresenter.getAll();
+    let ids = tabs.map(tab => tab.id);
+    this.tabPresenter.remove(ids);
+  }
+
+  async addbookmark(title) {
+    let tab = await this.tabPresenter.getCurrent();
+    let item = await this.bookmarkRepository.create(title, tab.url);
+    let message = 'Saved current page: ' + item.url;
+    return this.consoleClient.showInfo(tab.id, message);
+  }
+
+  async set(keywords) {
+    if (keywords.length === 0) {
+      return;
+    }
+    let [name, value] = parsers.parseSetOption(keywords, properties.types);
+    await this.settingRepository.setProperty(name, value);
+
+    return this.contentMessageClient.broadcastSettingsChanged();
+  }
+
+  async urlOrSearch(keywords) {
+    let settings = await this.settingRepository.get();
+    return urls.searchUrl(keywords, settings.search);
+  }
+}
diff --git a/src/background/usecases/CompletionsUseCase.js b/src/background/usecases/CompletionsUseCase.js
deleted file mode 100644
index 7dc30ac..0000000
--- a/src/background/usecases/CompletionsUseCase.js
+++ /dev/null
@@ -1,205 +0,0 @@
-import CompletionItem from '../domains/CompletionItem';
-import CompletionGroup from '../domains/CompletionGroup';
-import Completions from '../domains/Completions';
-import CommandDocs from '../domains/CommandDocs';
-import CompletionsRepository from '../repositories/CompletionsRepository';
-import * as filters from './filters';
-import SettingRepository from '../repositories/SettingRepository';
-import TabPresenter from '../presenters/TabPresenter';
-import * as properties from '../../shared/settings/properties';
-
-const COMPLETION_ITEM_LIMIT = 10;
-
-export default class CompletionsUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-    this.completionsRepository = new CompletionsRepository();
-    this.settingRepository = new SettingRepository();
-  }
-
-  queryConsoleCommand(prefix) {
-    let keys = Object.keys(CommandDocs);
-    let items = keys
-      .filter(name => name.startsWith(prefix))
-      .map(name => ({
-        caption: name,
-        content: name,
-        url: CommandDocs[name],
-      }));
-
-    if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
-    }
-    return Promise.resolve(
-      new Completions([new CompletionGroup('Console Command', items)])
-    );
-  }
-
-  async queryOpen(name, keywords) {
-    let settings = await this.settingRepository.get();
-    let groups = [];
-
-    let complete = settings.properties.complete || properties.defaults.complete;
-    for (let c of complete) {
-      if (c === 's') {
-        // eslint-disable-next-line no-await-in-loop
-        let engines = await this.querySearchEngineItems(name, keywords);
-        if (engines.length > 0) {
-          groups.push(new CompletionGroup('Search Engines', engines));
-        }
-      } else if (c === 'h') {
-        // eslint-disable-next-line no-await-in-loop
-        let histories = await this.queryHistoryItems(name, keywords);
-        if (histories.length > 0) {
-          groups.push(new CompletionGroup('History', histories));
-        }
-      } else if (c === 'b') {
-        // eslint-disable-next-line no-await-in-loop
-        let bookmarks = await this.queryBookmarkItems(name, keywords);
-        if (bookmarks.length > 0) {
-          groups.push(new CompletionGroup('Bookmarks', bookmarks));
-        }
-      }
-    }
-    return new Completions(groups);
-  }
-
-  // eslint-disable-next-line max-statements
-  async queryBuffer(name, keywords) {
-    let lastId = await this.tabPresenter.getLastSelectedId();
-    let trimmed = keywords.trim();
-    let tabs = [];
-    if (trimmed.length > 0 && !isNaN(trimmed)) {
-      let all = await this.tabPresenter.getAll();
-      let index = parseInt(trimmed, 10) - 1;
-      if (index >= 0 && index < all.length) {
-        tabs = [all[index]];
-      }
-    } else if (trimmed === '%') {
-      let all = await this.tabPresenter.getAll();
-      let tab = all.find(t => t.active);
-      tabs = [tab];
-    } else if (trimmed === '#') {
-      if (typeof lastId !== 'undefined' && lastId !== null) {
-        let all = await this.tabPresenter.getAll();
-        let tab = all.find(t => t.id === lastId);
-        tabs = [tab];
-      }
-    } else {
-      tabs = await this.completionsRepository.queryTabs(keywords, false);
-    }
-    const flag = (tab) => {
-      if (tab.active) {
-        return '%';
-      } else if (tab.id === lastId) {
-        return '#';
-      }
-      return ' ';
-    };
-    let items = tabs.map(tab => new CompletionItem({
-      caption: tab.index + 1 + ': ' + flag(tab) + ' ' + tab.title,
-      content: name + ' ' + tab.title,
-      url: tab.url,
-      icon: tab.favIconUrl
-    }));
-    if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
-    }
-    return new Completions([new CompletionGroup('Buffers', items)]);
-  }
-
-  queryBdelete(name, keywords) {
-    return this.queryTabs(name, true, keywords);
-  }
-
-  queryBdeleteForce(name, keywords) {
-    return this.queryTabs(name, false, keywords);
-  }
-
-  querySet(name, keywords) {
-    let items = Object.keys(properties.docs).map((key) => {
-      if (properties.types[key] === 'boolean') {
-        return [
-          new CompletionItem({
-            caption: key,
-            content: name + ' ' + key,
-            url: 'Enable ' + properties.docs[key],
-          }),
-          new CompletionItem({
-            caption: 'no' + key,
-            content: name + ' no' + key,
-            url: 'Disable ' + properties.docs[key],
-          }),
-        ];
-      }
-      return [
-        new CompletionItem({
-          caption: key,
-          content: name + ' ' + key,
-          url: 'Set ' + properties.docs[key],
-        })
-      ];
-    });
-    items = items.reduce((acc, val) => acc.concat(val), []);
-    items = items.filter((item) => {
-      return item.caption.startsWith(keywords);
-    });
-    if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
-    }
-    return Promise.resolve(
-      new Completions([new CompletionGroup('Properties', items)])
-    );
-  }
-
-  async queryTabs(name, excludePinned, args) {
-    let tabs = await this.completionsRepository.queryTabs(args, excludePinned);
-    let items = tabs.map(tab => new CompletionItem({
-      caption: tab.title,
-      content: name + ' ' + tab.title,
-      url: tab.url,
-      icon: tab.favIconUrl
-    }));
-    if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
-    }
-    return new Completions([new CompletionGroup('Buffers', items)]);
-  }
-
-  async querySearchEngineItems(name, keywords) {
-    let settings = await this.settingRepository.get();
-    let engines = Object.keys(settings.search.engines)
-      .filter(key => key.startsWith(keywords));
-    return engines.map(key => new CompletionItem({
-      caption: key,
-      content: name + ' ' + key,
-    }));
-  }
-
-  async queryHistoryItems(name, keywords) {
-    let histories = await this.completionsRepository.queryHistories(keywords);
-    histories = [histories]
-      .map(filters.filterBlankTitle)
-      .map(filters.filterHttp)
-      .map(filters.filterByTailingSlash)
-      .map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT))
-      .map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0]
-      .sort((x, y) => x.visitCount < y.visitCount)
-      .slice(0, COMPLETION_ITEM_LIMIT);
-    return histories.map(page => new CompletionItem({
-      caption: page.title,
-      content: name + ' ' + page.url,
-      url: page.url
-    }));
-  }
-
-  async queryBookmarkItems(name, keywords) {
-    let bookmarks = await this.completionsRepository.queryBookmarks(keywords);
-    return bookmarks.slice(0, COMPLETION_ITEM_LIMIT)
-      .map(page => new CompletionItem({
-        caption: page.title,
-        content: name + ' ' + page.url,
-        url: page.url
-      }));
-  }
-}
diff --git a/src/background/usecases/CompletionsUseCase.ts b/src/background/usecases/CompletionsUseCase.ts
new file mode 100644
index 0000000..7dc30ac
--- /dev/null
+++ b/src/background/usecases/CompletionsUseCase.ts
@@ -0,0 +1,205 @@
+import CompletionItem from '../domains/CompletionItem';
+import CompletionGroup from '../domains/CompletionGroup';
+import Completions from '../domains/Completions';
+import CommandDocs from '../domains/CommandDocs';
+import CompletionsRepository from '../repositories/CompletionsRepository';
+import * as filters from './filters';
+import SettingRepository from '../repositories/SettingRepository';
+import TabPresenter from '../presenters/TabPresenter';
+import * as properties from '../../shared/settings/properties';
+
+const COMPLETION_ITEM_LIMIT = 10;
+
+export default class CompletionsUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+    this.completionsRepository = new CompletionsRepository();
+    this.settingRepository = new SettingRepository();
+  }
+
+  queryConsoleCommand(prefix) {
+    let keys = Object.keys(CommandDocs);
+    let items = keys
+      .filter(name => name.startsWith(prefix))
+      .map(name => ({
+        caption: name,
+        content: name,
+        url: CommandDocs[name],
+      }));
+
+    if (items.length === 0) {
+      return Promise.resolve(Completions.empty());
+    }
+    return Promise.resolve(
+      new Completions([new CompletionGroup('Console Command', items)])
+    );
+  }
+
+  async queryOpen(name, keywords) {
+    let settings = await this.settingRepository.get();
+    let groups = [];
+
+    let complete = settings.properties.complete || properties.defaults.complete;
+    for (let c of complete) {
+      if (c === 's') {
+        // eslint-disable-next-line no-await-in-loop
+        let engines = await this.querySearchEngineItems(name, keywords);
+        if (engines.length > 0) {
+          groups.push(new CompletionGroup('Search Engines', engines));
+        }
+      } else if (c === 'h') {
+        // eslint-disable-next-line no-await-in-loop
+        let histories = await this.queryHistoryItems(name, keywords);
+        if (histories.length > 0) {
+          groups.push(new CompletionGroup('History', histories));
+        }
+      } else if (c === 'b') {
+        // eslint-disable-next-line no-await-in-loop
+        let bookmarks = await this.queryBookmarkItems(name, keywords);
+        if (bookmarks.length > 0) {
+          groups.push(new CompletionGroup('Bookmarks', bookmarks));
+        }
+      }
+    }
+    return new Completions(groups);
+  }
+
+  // eslint-disable-next-line max-statements
+  async queryBuffer(name, keywords) {
+    let lastId = await this.tabPresenter.getLastSelectedId();
+    let trimmed = keywords.trim();
+    let tabs = [];
+    if (trimmed.length > 0 && !isNaN(trimmed)) {
+      let all = await this.tabPresenter.getAll();
+      let index = parseInt(trimmed, 10) - 1;
+      if (index >= 0 && index < all.length) {
+        tabs = [all[index]];
+      }
+    } else if (trimmed === '%') {
+      let all = await this.tabPresenter.getAll();
+      let tab = all.find(t => t.active);
+      tabs = [tab];
+    } else if (trimmed === '#') {
+      if (typeof lastId !== 'undefined' && lastId !== null) {
+        let all = await this.tabPresenter.getAll();
+        let tab = all.find(t => t.id === lastId);
+        tabs = [tab];
+      }
+    } else {
+      tabs = await this.completionsRepository.queryTabs(keywords, false);
+    }
+    const flag = (tab) => {
+      if (tab.active) {
+        return '%';
+      } else if (tab.id === lastId) {
+        return '#';
+      }
+      return ' ';
+    };
+    let items = tabs.map(tab => new CompletionItem({
+      caption: tab.index + 1 + ': ' + flag(tab) + ' ' + tab.title,
+      content: name + ' ' + tab.title,
+      url: tab.url,
+      icon: tab.favIconUrl
+    }));
+    if (items.length === 0) {
+      return Promise.resolve(Completions.empty());
+    }
+    return new Completions([new CompletionGroup('Buffers', items)]);
+  }
+
+  queryBdelete(name, keywords) {
+    return this.queryTabs(name, true, keywords);
+  }
+
+  queryBdeleteForce(name, keywords) {
+    return this.queryTabs(name, false, keywords);
+  }
+
+  querySet(name, keywords) {
+    let items = Object.keys(properties.docs).map((key) => {
+      if (properties.types[key] === 'boolean') {
+        return [
+          new CompletionItem({
+            caption: key,
+            content: name + ' ' + key,
+            url: 'Enable ' + properties.docs[key],
+          }),
+          new CompletionItem({
+            caption: 'no' + key,
+            content: name + ' no' + key,
+            url: 'Disable ' + properties.docs[key],
+          }),
+        ];
+      }
+      return [
+        new CompletionItem({
+          caption: key,
+          content: name + ' ' + key,
+          url: 'Set ' + properties.docs[key],
+        })
+      ];
+    });
+    items = items.reduce((acc, val) => acc.concat(val), []);
+    items = items.filter((item) => {
+      return item.caption.startsWith(keywords);
+    });
+    if (items.length === 0) {
+      return Promise.resolve(Completions.empty());
+    }
+    return Promise.resolve(
+      new Completions([new CompletionGroup('Properties', items)])
+    );
+  }
+
+  async queryTabs(name, excludePinned, args) {
+    let tabs = await this.completionsRepository.queryTabs(args, excludePinned);
+    let items = tabs.map(tab => new CompletionItem({
+      caption: tab.title,
+      content: name + ' ' + tab.title,
+      url: tab.url,
+      icon: tab.favIconUrl
+    }));
+    if (items.length === 0) {
+      return Promise.resolve(Completions.empty());
+    }
+    return new Completions([new CompletionGroup('Buffers', items)]);
+  }
+
+  async querySearchEngineItems(name, keywords) {
+    let settings = await this.settingRepository.get();
+    let engines = Object.keys(settings.search.engines)
+      .filter(key => key.startsWith(keywords));
+    return engines.map(key => new CompletionItem({
+      caption: key,
+      content: name + ' ' + key,
+    }));
+  }
+
+  async queryHistoryItems(name, keywords) {
+    let histories = await this.completionsRepository.queryHistories(keywords);
+    histories = [histories]
+      .map(filters.filterBlankTitle)
+      .map(filters.filterHttp)
+      .map(filters.filterByTailingSlash)
+      .map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT))
+      .map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0]
+      .sort((x, y) => x.visitCount < y.visitCount)
+      .slice(0, COMPLETION_ITEM_LIMIT);
+    return histories.map(page => new CompletionItem({
+      caption: page.title,
+      content: name + ' ' + page.url,
+      url: page.url
+    }));
+  }
+
+  async queryBookmarkItems(name, keywords) {
+    let bookmarks = await this.completionsRepository.queryBookmarks(keywords);
+    return bookmarks.slice(0, COMPLETION_ITEM_LIMIT)
+      .map(page => new CompletionItem({
+        caption: page.title,
+        content: name + ' ' + page.url,
+        url: page.url
+      }));
+  }
+}
diff --git a/src/background/usecases/ConsoleUseCase.js b/src/background/usecases/ConsoleUseCase.js
deleted file mode 100644
index e8e5d4a..0000000
--- a/src/background/usecases/ConsoleUseCase.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import TabPresenter from '../presenters/TabPresenter';
-import ConsoleClient from '../infrastructures/ConsoleClient';
-
-export default class ConsoleUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-    this.consoleClient = new ConsoleClient();
-  }
-
-  async showCommand() {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.consoleClient.showCommand(tab.id, '');
-  }
-
-  async showOpenCommand(alter) {
-    let tab = await this.tabPresenter.getCurrent();
-    let command = 'open ';
-    if (alter) {
-      command += tab.url;
-    }
-    return this.consoleClient.showCommand(tab.id, command);
-  }
-
-  async showTabopenCommand(alter) {
-    let tab = await this.tabPresenter.getCurrent();
-    let command = 'tabopen ';
-    if (alter) {
-      command += tab.url;
-    }
-    return this.consoleClient.showCommand(tab.id, command);
-  }
-
-  async showWinopenCommand(alter) {
-    let tab = await this.tabPresenter.getCurrent();
-    let command = 'winopen ';
-    if (alter) {
-      command += tab.url;
-    }
-    return this.consoleClient.showCommand(tab.id, command);
-  }
-
-  async showBufferCommand() {
-    let tab = await this.tabPresenter.getCurrent();
-    let command = 'buffer ';
-    return this.consoleClient.showCommand(tab.id, command);
-  }
-
-  async showAddbookmarkCommand(alter) {
-    let tab = await this.tabPresenter.getCurrent();
-    let command = 'addbookmark ';
-    if (alter) {
-      command += tab.title;
-    }
-    return this.consoleClient.showCommand(tab.id, command);
-  }
-
-  async hideConsole() {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.consoleClient.hide(tab.id);
-  }
-}
diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts
new file mode 100644
index 0000000..e8e5d4a
--- /dev/null
+++ b/src/background/usecases/ConsoleUseCase.ts
@@ -0,0 +1,61 @@
+import TabPresenter from '../presenters/TabPresenter';
+import ConsoleClient from '../infrastructures/ConsoleClient';
+
+export default class ConsoleUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+    this.consoleClient = new ConsoleClient();
+  }
+
+  async showCommand() {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.consoleClient.showCommand(tab.id, '');
+  }
+
+  async showOpenCommand(alter) {
+    let tab = await this.tabPresenter.getCurrent();
+    let command = 'open ';
+    if (alter) {
+      command += tab.url;
+    }
+    return this.consoleClient.showCommand(tab.id, command);
+  }
+
+  async showTabopenCommand(alter) {
+    let tab = await this.tabPresenter.getCurrent();
+    let command = 'tabopen ';
+    if (alter) {
+      command += tab.url;
+    }
+    return this.consoleClient.showCommand(tab.id, command);
+  }
+
+  async showWinopenCommand(alter) {
+    let tab = await this.tabPresenter.getCurrent();
+    let command = 'winopen ';
+    if (alter) {
+      command += tab.url;
+    }
+    return this.consoleClient.showCommand(tab.id, command);
+  }
+
+  async showBufferCommand() {
+    let tab = await this.tabPresenter.getCurrent();
+    let command = 'buffer ';
+    return this.consoleClient.showCommand(tab.id, command);
+  }
+
+  async showAddbookmarkCommand(alter) {
+    let tab = await this.tabPresenter.getCurrent();
+    let command = 'addbookmark ';
+    if (alter) {
+      command += tab.title;
+    }
+    return this.consoleClient.showCommand(tab.id, command);
+  }
+
+  async hideConsole() {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.consoleClient.hide(tab.id);
+  }
+}
diff --git a/src/background/usecases/FindUseCase.js b/src/background/usecases/FindUseCase.js
deleted file mode 100644
index 224e4a9..0000000
--- a/src/background/usecases/FindUseCase.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import FindRepository from '../repositories/FindRepository';
-import TabPresenter from '../presenters/TabPresenter';
-import ConsoleClient from '../infrastructures/ConsoleClient';
-
-export default class FindUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-    this.findRepository = new FindRepository();
-    this.consoleClient = new ConsoleClient();
-  }
-
-  getKeyword() {
-    return this.findRepository.getKeyword();
-  }
-
-  setKeyword(keyword) {
-    return this.findRepository.setKeyword(keyword);
-  }
-
-  async findStart() {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.consoleClient.showFind(tab.id);
-  }
-}
diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts
new file mode 100644
index 0000000..224e4a9
--- /dev/null
+++ b/src/background/usecases/FindUseCase.ts
@@ -0,0 +1,24 @@
+import FindRepository from '../repositories/FindRepository';
+import TabPresenter from '../presenters/TabPresenter';
+import ConsoleClient from '../infrastructures/ConsoleClient';
+
+export default class FindUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+    this.findRepository = new FindRepository();
+    this.consoleClient = new ConsoleClient();
+  }
+
+  getKeyword() {
+    return this.findRepository.getKeyword();
+  }
+
+  setKeyword(keyword) {
+    return this.findRepository.setKeyword(keyword);
+  }
+
+  async findStart() {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.consoleClient.showFind(tab.id);
+  }
+}
diff --git a/src/background/usecases/LinkUseCase.js b/src/background/usecases/LinkUseCase.js
deleted file mode 100644
index 89412c5..0000000
--- a/src/background/usecases/LinkUseCase.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import SettingRepository from '../repositories/SettingRepository';
-import TabPresenter from '../presenters/TabPresenter';
-
-export default class LinkUseCase {
-  constructor() {
-    this.settingRepository = new SettingRepository();
-    this.tabPresenter = new TabPresenter();
-  }
-
-  openToTab(url, tabId) {
-    return this.tabPresenter.open(url, tabId);
-  }
-
-  openNewTab(url, openerId, background) {
-    return this.tabPresenter.create(url, {
-      openerTabId: openerId, active: !background
-    });
-  }
-}
diff --git a/src/background/usecases/LinkUseCase.ts b/src/background/usecases/LinkUseCase.ts
new file mode 100644
index 0000000..89412c5
--- /dev/null
+++ b/src/background/usecases/LinkUseCase.ts
@@ -0,0 +1,19 @@
+import SettingRepository from '../repositories/SettingRepository';
+import TabPresenter from '../presenters/TabPresenter';
+
+export default class LinkUseCase {
+  constructor() {
+    this.settingRepository = new SettingRepository();
+    this.tabPresenter = new TabPresenter();
+  }
+
+  openToTab(url, tabId) {
+    return this.tabPresenter.open(url, tabId);
+  }
+
+  openNewTab(url, openerId, background) {
+    return this.tabPresenter.create(url, {
+      openerTabId: openerId, active: !background
+    });
+  }
+}
diff --git a/src/background/usecases/MarkUseCase.js b/src/background/usecases/MarkUseCase.js
deleted file mode 100644
index 39c796b..0000000
--- a/src/background/usecases/MarkUseCase.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import GlobalMark from '../domains/GlobalMark';
-import TabPresenter from '../presenters/TabPresenter';
-import MarkRepository from '../repositories/MarkRepository';
-import ConsoleClient from '../infrastructures/ConsoleClient';
-import ContentMessageClient from '../infrastructures/ContentMessageClient';
-
-export default class MarkUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-    this.markRepository = new MarkRepository();
-    this.consoleClient = new ConsoleClient();
-    this.contentMessageClient = new ContentMessageClient();
-  }
-
-  async setGlobal(key, x, y) {
-    let tab = await this.tabPresenter.getCurrent();
-    let mark = new GlobalMark(tab.id, tab.url, x, y);
-    return this.markRepository.setMark(key, mark);
-  }
-
-  async jumpGlobal(key) {
-    let current = await this.tabPresenter.getCurrent();
-
-    let mark = await this.markRepository.getMark(key);
-    if (!mark) {
-      return this.consoleClient.showError(current.id, 'Mark is not set');
-    }
-
-    return this.contentMessageClient.scrollTo(
-      mark.tabId, mark.x, mark.y
-    ).then(() => {
-      return this.tabPresenter.select(mark.tabId);
-    }).catch(async() => {
-      let tab = await this.tabPresenter.create(mark.url);
-      let mark2 = new GlobalMark(tab.id, mark.url, mark.x, mark.y);
-      return this.markRepository.setMark(key, mark2);
-    });
-  }
-}
diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts
new file mode 100644
index 0000000..39c796b
--- /dev/null
+++ b/src/background/usecases/MarkUseCase.ts
@@ -0,0 +1,39 @@
+import GlobalMark from '../domains/GlobalMark';
+import TabPresenter from '../presenters/TabPresenter';
+import MarkRepository from '../repositories/MarkRepository';
+import ConsoleClient from '../infrastructures/ConsoleClient';
+import ContentMessageClient from '../infrastructures/ContentMessageClient';
+
+export default class MarkUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+    this.markRepository = new MarkRepository();
+    this.consoleClient = new ConsoleClient();
+    this.contentMessageClient = new ContentMessageClient();
+  }
+
+  async setGlobal(key, x, y) {
+    let tab = await this.tabPresenter.getCurrent();
+    let mark = new GlobalMark(tab.id, tab.url, x, y);
+    return this.markRepository.setMark(key, mark);
+  }
+
+  async jumpGlobal(key) {
+    let current = await this.tabPresenter.getCurrent();
+
+    let mark = await this.markRepository.getMark(key);
+    if (!mark) {
+      return this.consoleClient.showError(current.id, 'Mark is not set');
+    }
+
+    return this.contentMessageClient.scrollTo(
+      mark.tabId, mark.x, mark.y
+    ).then(() => {
+      return this.tabPresenter.select(mark.tabId);
+    }).catch(async() => {
+      let tab = await this.tabPresenter.create(mark.url);
+      let mark2 = new GlobalMark(tab.id, mark.url, mark.x, mark.y);
+      return this.markRepository.setMark(key, mark2);
+    });
+  }
+}
diff --git a/src/background/usecases/SettingUseCase.js b/src/background/usecases/SettingUseCase.js
deleted file mode 100644
index 9e17408..0000000
--- a/src/background/usecases/SettingUseCase.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import Setting from '../domains/Setting';
-// eslint-disable-next-line max-len
-import PersistentSettingRepository from '../repositories/PersistentSettingRepository';
-import SettingRepository from '../repositories/SettingRepository';
-
-export default class SettingUseCase {
-  constructor() {
-    this.persistentSettingRepository = new PersistentSettingRepository();
-    this.settingRepository = new SettingRepository();
-  }
-
-  get() {
-    return this.settingRepository.get();
-  }
-
-  async reload() {
-    let settings = await this.persistentSettingRepository.load();
-    if (!settings) {
-      settings = Setting.defaultSettings();
-    }
-
-    let value = settings.value();
-
-    this.settingRepository.update(value);
-
-    return value;
-  }
-}
diff --git a/src/background/usecases/SettingUseCase.ts b/src/background/usecases/SettingUseCase.ts
new file mode 100644
index 0000000..9e17408
--- /dev/null
+++ b/src/background/usecases/SettingUseCase.ts
@@ -0,0 +1,28 @@
+import Setting from '../domains/Setting';
+// eslint-disable-next-line max-len
+import PersistentSettingRepository from '../repositories/PersistentSettingRepository';
+import SettingRepository from '../repositories/SettingRepository';
+
+export default class SettingUseCase {
+  constructor() {
+    this.persistentSettingRepository = new PersistentSettingRepository();
+    this.settingRepository = new SettingRepository();
+  }
+
+  get() {
+    return this.settingRepository.get();
+  }
+
+  async reload() {
+    let settings = await this.persistentSettingRepository.load();
+    if (!settings) {
+      settings = Setting.defaultSettings();
+    }
+
+    let value = settings.value();
+
+    this.settingRepository.update(value);
+
+    return value;
+  }
+}
diff --git a/src/background/usecases/TabSelectUseCase.js b/src/background/usecases/TabSelectUseCase.js
deleted file mode 100644
index 16b3e14..0000000
--- a/src/background/usecases/TabSelectUseCase.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import TabPresenter from '../presenters/TabPresenter';
-
-export default class TabSelectUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-  }
-
-  async selectPrev(count) {
-    let tabs = await this.tabPresenter.getAll();
-    if (tabs.length < 2) {
-      return;
-    }
-    let tab = tabs.find(t => t.active);
-    if (!tab) {
-      return;
-    }
-    let select = (tab.index - count + tabs.length) % tabs.length;
-    return this.tabPresenter.select(tabs[select].id);
-  }
-
-  async selectNext(count) {
-    let tabs = await this.tabPresenter.getAll();
-    if (tabs.length < 2) {
-      return;
-    }
-    let tab = tabs.find(t => t.active);
-    if (!tab) {
-      return;
-    }
-    let select = (tab.index + count) % tabs.length;
-    return this.tabPresenter.select(tabs[select].id);
-  }
-
-  async selectFirst() {
-    let tabs = await this.tabPresenter.getAll();
-    return this.tabPresenter.select(tabs[0].id);
-  }
-
-  async selectLast() {
-    let tabs = await this.tabPresenter.getAll();
-    return this.tabPresenter.select(tabs[tabs.length - 1].id);
-  }
-
-  async selectPrevSelected() {
-    let tabId = await this.tabPresenter.getLastSelectedId();
-    if (tabId === null || typeof tabId === 'undefined') {
-      return;
-    }
-    this.tabPresenter.select(tabId);
-  }
-}
diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts
new file mode 100644
index 0000000..16b3e14
--- /dev/null
+++ b/src/background/usecases/TabSelectUseCase.ts
@@ -0,0 +1,51 @@
+import TabPresenter from '../presenters/TabPresenter';
+
+export default class TabSelectUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+  }
+
+  async selectPrev(count) {
+    let tabs = await this.tabPresenter.getAll();
+    if (tabs.length < 2) {
+      return;
+    }
+    let tab = tabs.find(t => t.active);
+    if (!tab) {
+      return;
+    }
+    let select = (tab.index - count + tabs.length) % tabs.length;
+    return this.tabPresenter.select(tabs[select].id);
+  }
+
+  async selectNext(count) {
+    let tabs = await this.tabPresenter.getAll();
+    if (tabs.length < 2) {
+      return;
+    }
+    let tab = tabs.find(t => t.active);
+    if (!tab) {
+      return;
+    }
+    let select = (tab.index + count) % tabs.length;
+    return this.tabPresenter.select(tabs[select].id);
+  }
+
+  async selectFirst() {
+    let tabs = await this.tabPresenter.getAll();
+    return this.tabPresenter.select(tabs[0].id);
+  }
+
+  async selectLast() {
+    let tabs = await this.tabPresenter.getAll();
+    return this.tabPresenter.select(tabs[tabs.length - 1].id);
+  }
+
+  async selectPrevSelected() {
+    let tabId = await this.tabPresenter.getLastSelectedId();
+    if (tabId === null || typeof tabId === 'undefined') {
+      return;
+    }
+    this.tabPresenter.select(tabId);
+  }
+}
diff --git a/src/background/usecases/TabUseCase.js b/src/background/usecases/TabUseCase.js
deleted file mode 100644
index d930842..0000000
--- a/src/background/usecases/TabUseCase.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import TabPresenter from '../presenters/TabPresenter';
-import BrowserSettingRepository from '../repositories/BrowserSettingRepository';
-
-export default class TabUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-    this.browserSettingRepository = new BrowserSettingRepository();
-  }
-
-  async close(force) {
-    let tab = await this.tabPresenter.getCurrent();
-    if (!force && tab.pinned) {
-      return;
-    }
-    return this.tabPresenter.remove([tab.id]);
-  }
-
-  async closeRight() {
-    let tabs = await this.tabPresenter.getAll();
-    tabs.sort((t1, t2) => t1.index - t2.index);
-    let index = tabs.findIndex(t => t.active);
-    if (index < 0) {
-      return;
-    }
-    for (let i = index + 1; i < tabs.length; ++i) {
-      let tab = tabs[i];
-      if (!tab.pinned) {
-        this.tabPresenter.remove(tab.id);
-      }
-    }
-  }
-
-  reopen() {
-    return this.tabPresenter.reopen();
-  }
-
-  async reload(cache) {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.reload(tab.id, cache);
-  }
-
-  async setPinned(pinned) {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.setPinned(tab.id, pinned);
-  }
-
-  async togglePinned() {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.setPinned(tab.id, !tab.pinned);
-  }
-
-  async duplicate() {
-    let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.duplicate(tab.id);
-  }
-
-  async openPageSource() {
-    let tab = await this.tabPresenter.getCurrent();
-    let url = 'view-source:' + tab.url;
-    return this.tabPresenter.create(url);
-  }
-
-  async openHome(newTab) {
-    let tab = await this.tabPresenter.getCurrent();
-    let urls = await this.browserSettingRepository.getHomepageUrls();
-    if (urls.length === 1 && urls[0] === 'about:home') {
-      // eslint-disable-next-line max-len
-      throw new Error('Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs');
-    }
-    if (urls.length === 1 && !newTab) {
-      return this.tabPresenter.open(urls[0], tab.id);
-    }
-    for (let url of urls) {
-      this.tabPresenter.create(url);
-    }
-  }
-}
diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts
new file mode 100644
index 0000000..d930842
--- /dev/null
+++ b/src/background/usecases/TabUseCase.ts
@@ -0,0 +1,77 @@
+import TabPresenter from '../presenters/TabPresenter';
+import BrowserSettingRepository from '../repositories/BrowserSettingRepository';
+
+export default class TabUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+    this.browserSettingRepository = new BrowserSettingRepository();
+  }
+
+  async close(force) {
+    let tab = await this.tabPresenter.getCurrent();
+    if (!force && tab.pinned) {
+      return;
+    }
+    return this.tabPresenter.remove([tab.id]);
+  }
+
+  async closeRight() {
+    let tabs = await this.tabPresenter.getAll();
+    tabs.sort((t1, t2) => t1.index - t2.index);
+    let index = tabs.findIndex(t => t.active);
+    if (index < 0) {
+      return;
+    }
+    for (let i = index + 1; i < tabs.length; ++i) {
+      let tab = tabs[i];
+      if (!tab.pinned) {
+        this.tabPresenter.remove(tab.id);
+      }
+    }
+  }
+
+  reopen() {
+    return this.tabPresenter.reopen();
+  }
+
+  async reload(cache) {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.tabPresenter.reload(tab.id, cache);
+  }
+
+  async setPinned(pinned) {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.tabPresenter.setPinned(tab.id, pinned);
+  }
+
+  async togglePinned() {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.tabPresenter.setPinned(tab.id, !tab.pinned);
+  }
+
+  async duplicate() {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.tabPresenter.duplicate(tab.id);
+  }
+
+  async openPageSource() {
+    let tab = await this.tabPresenter.getCurrent();
+    let url = 'view-source:' + tab.url;
+    return this.tabPresenter.create(url);
+  }
+
+  async openHome(newTab) {
+    let tab = await this.tabPresenter.getCurrent();
+    let urls = await this.browserSettingRepository.getHomepageUrls();
+    if (urls.length === 1 && urls[0] === 'about:home') {
+      // eslint-disable-next-line max-len
+      throw new Error('Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs');
+    }
+    if (urls.length === 1 && !newTab) {
+      return this.tabPresenter.open(urls[0], tab.id);
+    }
+    for (let url of urls) {
+      this.tabPresenter.create(url);
+    }
+  }
+}
diff --git a/src/background/usecases/VersionUseCase.js b/src/background/usecases/VersionUseCase.js
deleted file mode 100644
index ed5112b..0000000
--- a/src/background/usecases/VersionUseCase.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import manifest from '../../../manifest.json';
-import TabPresenter from '../presenters/TabPresenter';
-import NotifyPresenter from '../presenters/NotifyPresenter';
-
-export default class VersionUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-    this.notifyPresenter = new NotifyPresenter();
-  }
-
-  notify() {
-    let title = `Vim Vixen ${manifest.version} has been installed`;
-    let message = 'Click here to see release notes';
-    let url = this.releaseNoteUrl(manifest.version);
-    this.notifyPresenter.notify(title, message, () => {
-      this.tabPresenter.create(url);
-    });
-  }
-
-  releaseNoteUrl(version) {
-    if (version) {
-      return `https://github.com/ueokande/vim-vixen/releases/tag/${version}`;
-    }
-    return 'https://github.com/ueokande/vim-vixen/releases/';
-  }
-}
diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts
new file mode 100644
index 0000000..ed5112b
--- /dev/null
+++ b/src/background/usecases/VersionUseCase.ts
@@ -0,0 +1,26 @@
+import manifest from '../../../manifest.json';
+import TabPresenter from '../presenters/TabPresenter';
+import NotifyPresenter from '../presenters/NotifyPresenter';
+
+export default class VersionUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+    this.notifyPresenter = new NotifyPresenter();
+  }
+
+  notify() {
+    let title = `Vim Vixen ${manifest.version} has been installed`;
+    let message = 'Click here to see release notes';
+    let url = this.releaseNoteUrl(manifest.version);
+    this.notifyPresenter.notify(title, message, () => {
+      this.tabPresenter.create(url);
+    });
+  }
+
+  releaseNoteUrl(version) {
+    if (version) {
+      return `https://github.com/ueokande/vim-vixen/releases/tag/${version}`;
+    }
+    return 'https://github.com/ueokande/vim-vixen/releases/';
+  }
+}
diff --git a/src/background/usecases/ZoomUseCase.js b/src/background/usecases/ZoomUseCase.js
deleted file mode 100644
index 692d6d9..0000000
--- a/src/background/usecases/ZoomUseCase.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import TabPresenter from '../presenters/TabPresenter';
-
-const ZOOM_SETTINGS = [
-  0.33, 0.50, 0.66, 0.75, 0.80, 0.90, 1.00,
-  1.10, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00
-];
-
-export default class ZoomUseCase {
-  constructor() {
-    this.tabPresenter = new TabPresenter();
-  }
-
-  async zoomIn(tabId) {
-    let tab = await this.tabPresenter.getCurrent();
-    let current = await this.tabPresenter.getZoom(tab.id);
-    let factor = ZOOM_SETTINGS.find(f => f > current);
-    if (factor) {
-      return this.tabPresenter.setZoom(tabId, factor);
-    }
-  }
-
-  async zoomOut(tabId) {
-    let tab = await this.tabPresenter.getCurrent();
-    let current = await this.tabPresenter.getZoom(tab.id);
-    let factor = [].concat(ZOOM_SETTINGS).reverse().find(f => f < current);
-    if (factor) {
-      return this.tabPresenter.setZoom(tabId, factor);
-    }
-  }
-
-  zoomNutoral(tabId) {
-    return this.tabPresenter.setZoom(tabId, 1);
-  }
-
-}
diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts
new file mode 100644
index 0000000..692d6d9
--- /dev/null
+++ b/src/background/usecases/ZoomUseCase.ts
@@ -0,0 +1,35 @@
+import TabPresenter from '../presenters/TabPresenter';
+
+const ZOOM_SETTINGS = [
+  0.33, 0.50, 0.66, 0.75, 0.80, 0.90, 1.00,
+  1.10, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00
+];
+
+export default class ZoomUseCase {
+  constructor() {
+    this.tabPresenter = new TabPresenter();
+  }
+
+  async zoomIn(tabId) {
+    let tab = await this.tabPresenter.getCurrent();
+    let current = await this.tabPresenter.getZoom(tab.id);
+    let factor = ZOOM_SETTINGS.find(f => f > current);
+    if (factor) {
+      return this.tabPresenter.setZoom(tabId, factor);
+    }
+  }
+
+  async zoomOut(tabId) {
+    let tab = await this.tabPresenter.getCurrent();
+    let current = await this.tabPresenter.getZoom(tab.id);
+    let factor = [].concat(ZOOM_SETTINGS).reverse().find(f => f < current);
+    if (factor) {
+      return this.tabPresenter.setZoom(tabId, factor);
+    }
+  }
+
+  zoomNutoral(tabId) {
+    return this.tabPresenter.setZoom(tabId, 1);
+  }
+
+}
diff --git a/src/background/usecases/filters.js b/src/background/usecases/filters.js
deleted file mode 100644
index d057dca..0000000
--- a/src/background/usecases/filters.js
+++ /dev/null
@@ -1,72 +0,0 @@
-const filterHttp = (items) => {
-  let httpsHosts = items.map(x => new URL(x.url))
-    .filter(x => x.protocol === 'https:')
-    .map(x => x.host);
-  httpsHosts = new Set(httpsHosts);
-
-  return items.filter((item) => {
-    let url = new URL(item.url);
-    return url.protocol === 'https:' || !httpsHosts.has(url.host);
-  });
-};
-
-const filterBlankTitle = (items) => {
-  return items.filter(item => item.title && item.title !== '');
-};
-
-const filterByTailingSlash = (items) => {
-  let urls = items.map(item => new URL(item.url));
-  let simplePaths = urls
-    .filter(url => url.hash === '' && url.search === '')
-    .map(url => url.origin + url.pathname);
-  simplePaths = new Set(simplePaths);
-
-  return items.filter((item) => {
-    let url = new URL(item.url);
-    if (url.hash !== '' || url.search !== '' ||
-      url.pathname.slice(-1) !== '/') {
-      return true;
-    }
-    return !simplePaths.has(url.origin + url.pathname.slice(0, -1));
-  });
-};
-
-const filterByPathname = (items, min) => {
-  let hash = {};
-  for (let item of items) {
-    let url = new URL(item.url);
-    let pathname = url.origin + url.pathname;
-    if (!hash[pathname]) {
-      hash[pathname] = item;
-    } else if (hash[pathname].url.length > item.url.length) {
-      hash[pathname] = item;
-    }
-  }
-  let filtered = Object.values(hash);
-  if (filtered.length < min) {
-    return items;
-  }
-  return filtered;
-};
-
-const filterByOrigin = (items, min) => {
-  let hash = {};
-  for (let item of items) {
-    let origin = new URL(item.url).origin;
-    if (!hash[origin]) {
-      hash[origin] = item;
-    } else if (hash[origin].url.length > item.url.length) {
-      hash[origin] = item;
-    }
-  }
-  let filtered = Object.values(hash);
-  if (filtered.length < min) {
-    return items;
-  }
-  return filtered;
-};
-
-export {
-  filterHttp, filterBlankTitle, filterByTailingSlash,
-  filterByPathname, filterByOrigin
-};
diff --git a/src/background/usecases/filters.ts b/src/background/usecases/filters.ts
new file mode 100644
index 0000000..d057dca
--- /dev/null
+++ b/src/background/usecases/filters.ts
@@ -0,0 +1,72 @@
+const filterHttp = (items) => {
+  let httpsHosts = items.map(x => new URL(x.url))
+    .filter(x => x.protocol === 'https:')
+    .map(x => x.host);
+  httpsHosts = new Set(httpsHosts);
+
+  return items.filter((item) => {
+    let url = new URL(item.url);
+    return url.protocol === 'https:' || !httpsHosts.has(url.host);
+  });
+};
+
+const filterBlankTitle = (items) => {
+  return items.filter(item => item.title && item.title !== '');
+};
+
+const filterByTailingSlash = (items) => {
+  let urls = items.map(item => new URL(item.url));
+  let simplePaths = urls
+    .filter(url => url.hash === '' && url.search === '')
+    .map(url => url.origin + url.pathname);
+  simplePaths = new Set(simplePaths);
+
+  return items.filter((item) => {
+    let url = new URL(item.url);
+    if (url.hash !== '' || url.search !== '' ||
+      url.pathname.slice(-1) !== '/') {
+      return true;
+    }
+    return !simplePaths.has(url.origin + url.pathname.slice(0, -1));
+  });
+};
+
+const filterByPathname = (items, min) => {
+  let hash = {};
+  for (let item of items) {
+    let url = new URL(item.url);
+    let pathname = url.origin + url.pathname;
+    if (!hash[pathname]) {
+      hash[pathname] = item;
+    } else if (hash[pathname].url.length > item.url.length) {
+      hash[pathname] = item;
+    }
+  }
+  let filtered = Object.values(hash);
+  if (filtered.length < min) {
+    return items;
+  }
+  return filtered;
+};
+
+const filterByOrigin = (items, min) => {
+  let hash = {};
+  for (let item of items) {
+    let origin = new URL(item.url).origin;
+    if (!hash[origin]) {
+      hash[origin] = item;
+    } else if (hash[origin].url.length > item.url.length) {
+      hash[origin] = item;
+    }
+  }
+  let filtered = Object.values(hash);
+  if (filtered.length < min) {
+    return items;
+  }
+  return filtered;
+};
+
+export {
+  filterHttp, filterBlankTitle, filterByTailingSlash,
+  filterByPathname, filterByOrigin
+};
diff --git a/src/background/usecases/parsers.js b/src/background/usecases/parsers.js
deleted file mode 100644
index 43c8177..0000000
--- a/src/background/usecases/parsers.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 parseSetOption = (word, types) => {
-  let [key, value] = word.split('=');
-  if (value === undefined) {
-    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 { parseSetOption };
diff --git a/src/background/usecases/parsers.ts b/src/background/usecases/parsers.ts
new file mode 100644
index 0000000..43c8177
--- /dev/null
+++ b/src/background/usecases/parsers.ts
@@ -0,0 +1,31 @@
+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 === undefined) {
+    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 { parseSetOption };
-- 
cgit v1.2.3