My First Clean Architecture
This commit is contained in:
parent
4d4aaa2c4b
commit
bf7c125fb2
8 changed files with 185 additions and 3 deletions
|
@ -3,7 +3,6 @@ import * as commandActions from 'background/actions/command';
|
||||||
import * as settingActions from 'background/actions/setting';
|
import * as settingActions from 'background/actions/setting';
|
||||||
import * as findActions from 'background/actions/find';
|
import * as findActions from 'background/actions/find';
|
||||||
import * as tabActions from 'background/actions/tab';
|
import * as tabActions from 'background/actions/tab';
|
||||||
import * as completions from '../shared/completions';
|
|
||||||
|
|
||||||
export default class BackgroundComponent {
|
export default class BackgroundComponent {
|
||||||
constructor(store) {
|
constructor(store) {
|
||||||
|
@ -41,8 +40,6 @@ export default class BackgroundComponent {
|
||||||
return this.broadcastSettingsChanged();
|
return this.broadcastSettingsChanged();
|
||||||
case messages.SETTINGS_QUERY:
|
case messages.SETTINGS_QUERY:
|
||||||
return Promise.resolve(this.store.getState().setting.value);
|
return Promise.resolve(this.store.getState().setting.value);
|
||||||
case messages.CONSOLE_QUERY_COMPLETIONS:
|
|
||||||
return completions.complete(message.text, settings.value);
|
|
||||||
case messages.SETTINGS_RELOAD:
|
case messages.SETTINGS_RELOAD:
|
||||||
this.store.dispatch(settingActions.load());
|
this.store.dispatch(settingActions.load());
|
||||||
return this.broadcastSettingsChanged();
|
return this.broadcastSettingsChanged();
|
||||||
|
|
42
src/background/controllers/completions.js
Normal file
42
src/background/controllers/completions.js
Normal file
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
14
src/background/domains/completion-group.js
Normal file
14
src/background/domains/completion-group.js
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
24
src/background/domains/completion-item.js
Normal file
24
src/background/domains/completion-item.js
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
27
src/background/domains/completions.js
Normal file
27
src/background/domains/completions.js
Normal file
|
@ -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 promise from 'redux-promise';
|
||||||
import * as versions from './shared/versions';
|
import * as versions from './shared/versions';
|
||||||
|
|
||||||
|
import ContentMessageListener from './infrastructures/content-message-listener';
|
||||||
|
|
||||||
const store = createStore(
|
const store = createStore(
|
||||||
reducers,
|
reducers,
|
||||||
applyMiddleware(promise),
|
applyMiddleware(promise),
|
||||||
|
@ -32,3 +34,5 @@ const indicatorComponent = new IndicatorComponent(store);
|
||||||
store.dispatch(settingActions.load());
|
store.dispatch(settingActions.load());
|
||||||
|
|
||||||
checkAndNotifyUpdated();
|
checkAndNotifyUpdated();
|
||||||
|
|
||||||
|
new ContentMessageListener().run();
|
||||||
|
|
34
src/background/infrastructures/content-message-listener.js
Normal file
34
src/background/infrastructures/content-message-listener.js
Normal file
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
40
src/background/usecases/completions.js
Normal file
40
src/background/usecases/completions.js
Normal file
|
@ -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)];
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue