My First Clean Architecture

jh-changes
Shin'ya Ueoka 6 years ago
parent 4d4aaa2c4b
commit bf7c125fb2
  1. 3
      src/background/components/background.js
  2. 42
      src/background/controllers/completions.js
  3. 14
      src/background/domains/completion-group.js
  4. 24
      src/background/domains/completion-item.js
  5. 27
      src/background/domains/completions.js
  6. 4
      src/background/index.js
  7. 34
      src/background/infrastructures/content-message-listener.js
  8. 40
      src/background/usecases/completions.js

@ -3,7 +3,6 @@ import * as commandActions from 'background/actions/command';
import * as settingActions from 'background/actions/setting';
import * as findActions from 'background/actions/find';
import * as tabActions from 'background/actions/tab';
import * as completions from '../shared/completions';
export default class BackgroundComponent {
constructor(store) {
@ -41,8 +40,6 @@ export default class BackgroundComponent {
return this.broadcastSettingsChanged();
case messages.SETTINGS_QUERY:
return Promise.resolve(this.store.getState().setting.value);
case messages.CONSOLE_QUERY_COMPLETIONS:
return completions.complete(message.text, settings.value);
case messages.SETTINGS_RELOAD:
this.store.dispatch(settingActions.load());
return this.broadcastSettingsChanged();

@ -0,0 +1,42 @@
import CompletionsInteractor from '../usecases/completions';
import Completions from '../domains/completions';
export default class ContentMessageController {
constructor() {
this.completionsInteractor = new CompletionsInteractor();
}
getCompletions(line) {
let trimmed = line.trimStart();
let words = trimmed.split(/ +/);
let name = words[0];
if (words.length === 1) {
return this.completionsInteractor.queryConsoleCommand(name);
}
switch (words[0]) {
case 'o':
case 'open':
case 't':
case 'tabopen':
case 'w':
case 'winopen':
break;
case 'b':
case 'buffer':
break;
case 'bd!':
case 'bdel!':
case 'bdelete!':
case 'bdeletes!':
break;
case 'bd':
case 'bdel':
case 'bdelete':
case 'bdeletes':
break;
case 'set':
break;
}
return Promise.resolve(Completions.empty());
}
}

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

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

@ -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_COMPLETIONS = new Completions([]);
static empty() {
return Completions.EMPTY_COMPLETIONS;
}
}

@ -8,6 +8,8 @@ import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise';
import * as versions from './shared/versions';
import ContentMessageListener from './infrastructures/content-message-listener';
const store = createStore(
reducers,
applyMiddleware(promise),
@ -32,3 +34,5 @@ const indicatorComponent = new IndicatorComponent(store);
store.dispatch(settingActions.load());
checkAndNotifyUpdated();
new ContentMessageListener().run();

@ -0,0 +1,34 @@
import messages from '../../shared/messages';
import CompletionsController from '../controllers/completions';
export default class ContentMessageListener {
constructor() {
this.completionsController = new CompletionsController();
}
run() {
browser.runtime.onMessage.addListener((message, sender) => {
try {
return this.onMessage(message, sender);
} catch (e) {
return browser.tabs.sendMessage(sender.tab.id, {
type: messages.CONSOLE_SHOW_ERROR,
text: e.message,
});
}
});
}
onMessage(message) {
switch (message.type) {
case messages.CONSOLE_QUERY_COMPLETIONS:
return this.onConsoleQueryCompletions(message);
}
}
async onConsoleQueryCompletions(message) {
let completions =
await this.completionsController.getCompletions(message.text);
return Promise.resolve(completions.serialize());
}
}

@ -0,0 +1,40 @@
import CompletionItem from '../domains/completion-item';
import CompletionGroup from '../domains/completion-group';
import Completions from '../domains/completions';
import CompletionRepository from '../repositories/completions';
import CommandDocs from 'background/shared/commands/docs';
export default class CompletionsInteractor {
constructor() {
this.completionRepository = new CompletionRepository();
}
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 queryBdeleteCommand(name, force, args) {
let tabs = await this.completionRepository.queryTabs(args);
let items = tabs.map(tab => new CompletionItem({
caption: tab.title,
content: name + ' ' + tab.title,
url: tab.url,
icon: tab.favIconUrl
}));
return [new CompletionGroup('Buffers', items)];
}
}