more strict lint

jh-changes
Shin'ya Ueoka 7 years ago
parent c5529958d5
commit 9ae814dfe4
  1. 33
      .eslintrc
  2. 59
      src/actions/command.js
  3. 22
      src/actions/console.js
  4. 12
      src/actions/input.js
  5. 10
      src/actions/operation.js
  6. 30
      src/background/index.js
  7. 12
      src/background/keys.js
  8. 32
      src/background/tabs.js
  9. 9
      src/console/completion.js
  10. 60
      src/console/console.js
  11. 4
      src/console/frames.js
  12. 32
      src/content/follow.js
  13. 6
      src/content/hint-key-producer.js
  14. 5
      src/content/hint.js
  15. 4
      src/content/histories.js
  16. 8
      src/content/index.js
  17. 4
      src/content/scrolls.js
  18. 6
      src/operations/index.js
  19. 2
      src/reducers/console.js
  20. 10
      src/reducers/input.js
  21. 8
      src/store/index.js

@ -11,28 +11,47 @@
"jsx": true
}
},
"extends": [ "eslint:recommended" ],
"extends": [ "eslint:all" ],
"rules": {
"array-bracket-newline": ["error", { "multiline": true }],
"arrow-body-style": "off",
"array-element-newline": "off",
"arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"comma-dangle": "off",
"consistent-return": "off",
"default-case": "off",
"id-length": "off",
"indent": ["error", 2],
"max-statements": ["error", 15],
"multiline-ternary": "off",
"newline-after-var": "off",
"newline-before-return": "off",
"multiline-ternary": "off",
"max-statements": ["error", 15],
"no-console": "off",
"no-param-reassign": "off",
"no-magic-numbers": "off",
"no-bitwise": "off",
"no-use-before-define": "off",
"no-warning-comments": "off",
"no-console": ["error", { "allow": ["warn", "error"] }],
"no-empty-function": "off",
"no-mixed-operators": "off",
"no-plusplus": "off",
"capitalized-comments": "off",
"no-ternary": "off",
"no-undefined": "off",
"object-curly-spacing": [
"error",
"always", { "arraysInObjects": false, "objectsInObjects": false }
],
"object-curly-newline": "off",
"object-property-newline": "off",
"object-curly-newline": ["error", { "consistent": true }],
"object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
"object-shorthand": "off",
"one-var": "off",
"padded-blocks": "off",
"prefer-const": "off",
"prefer-destructuring": ["error", { "AssignmentExpression": {"array": false}}],
"prefer-template": "off",
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"quote-props": "off",
"require-jsdoc": "off",
"sort-imports": "off",
"sort-keys": "off",

@ -3,36 +3,39 @@ import * as consoleActions from './console';
const normalizeUrl = (string) => {
try {
return new URL(string).href
return new URL(string).href;
} catch (e) {
return 'http://' + string;
}
}
};
const openCommand = (url) => {
return browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
if (tabs.length > 0) {
return browser.tabs.update(tabs[0].id, { url: url });
return browser.tabs.query({
active: true, currentWindow: true
}).then((gotTabs) => {
if (gotTabs.length > 0) {
return browser.tabs.update(gotTabs[0].id, { url: url });
}
});
}
};
const tabopenCommand = (url) => {
return browser.tabs.create({ url: url });
}
};
const bufferCommand = (keywords) => {
return browser.tabs.query({ active: true, currentWindow: true }).then((tabss) => {
if (tabss.length > 0) {
return browser.tabs.query({
active: true, currentWindow: true
}).then((gotTabs) => {
if (gotTabs.length > 0) {
if (isNaN(keywords)) {
return tabs.selectByKeyword(tabss[0], keywords);
} else {
let index = parseInt(keywords, 10) - 1;
return tabs.selectAt(index);
return tabs.selectByKeyword(gotTabs[0], keywords);
}
let index = parseInt(keywords, 10) - 1;
return tabs.selectAt(index);
}
});
}
};
const doCommand = (name, remaining) => {
switch (name) {
@ -46,39 +49,43 @@ const doCommand = (name, remaining) => {
return bufferCommand(remaining);
}
throw new Error(name + ' command is not defined');
}
};
const getCompletions = (command, keywords) => {
switch (command) {
case 'buffer':
return tabs.getCompletions(keywords).then((tabs) => {
let items = tabs.map((tab) => {
return tabs.getCompletions(keywords).then((gotTabs) => {
let items = gotTabs.map((tab) => {
return {
caption: tab.title,
content: tab.title,
url: tab.url,
icon: tab.favIconUrl
}
};
});
return [{
name: "Buffers",
items: items
}];
return [
{
name: 'Buffers',
items: items
}
];
});
}
return Promise.resolve([]);
};
export function exec(line) {
const exec = (line) => {
let name = line.split(' ')[0];
let remaining = line.replace(name + ' ', '');
return doCommand(name, remaining).then(() => {
return consoleActions.hide();
});
}
};
export function complete(line) {
const complete = (line) => {
let command = line.split(' ', 1)[0];
let keywords = line.replace(command + ' ', '');
return getCompletions(command, keywords).then(consoleActions.setCompletions);
}
};
export { exec, complete };

@ -1,28 +1,30 @@
import actions from '../actions';
export function showCommand(text) {
const showCommand = (text) => {
return {
type: actions.CONSOLE_SHOW_COMMAND,
text: text
};
}
};
export function setCompletions(completions) {
return {
const setCompletions = (completions) => {
return {
type: actions.CONSOLE_SET_COMPLETIONS,
completions: completions
};
}
};
export function showError(text) {
const showError = (text) => {
return {
type: actions.CONSOLE_SHOW_ERROR,
text: text
};
}
};
export function hide() {
return {
const hide = () => {
return {
type: actions.CONSOLE_HIDE
};
}
};
export { showCommand, setCompletions, showError, hide };

@ -1,15 +1,17 @@
import actions from '../actions';
export function keyPress(code, ctrl) {
const keyPress = (code, ctrl) => {
return {
type: actions.INPUT_KEY_PRESS,
code,
ctrl
};
}
};
export function clearKeys() {
const clearKeys = () => {
return {
type: actions.INPUT_CLEAR_KEYS
}
}
};
};
export { keyPress, clearKeys };

@ -1,10 +1,10 @@
import operations from '../operations';
import messages from '../messages';
import messages from '../messages';
import * as consoleActions from './console';
import * as tabs from '../background/tabs';
import * as zooms from '../background/zooms';
export function exec(operation, tab) {
const exec = (operation, tab) => {
switch (operation.type) {
case operations.TABS_CLOSE:
return tabs.closeTab(tab.id);
@ -28,9 +28,8 @@ export function exec(operation, tab) {
if (operations.alter) {
// alter url
return consoleActions.showCommand('open ' + tab.url);
} else {
return consoleActions.showCommand('open ');
}
return consoleActions.showCommand('open ');
case operations.COMMAND_BUFFER:
return consoleActions.showCommand('buffer ');
default:
@ -39,5 +38,6 @@ export function exec(operation, tab) {
operation
});
}
}
};
export { exec };

@ -5,9 +5,10 @@ import * as commandActions from '../actions/command';
import * as consoleActions from '../actions/console';
import reducers from '../reducers';
import messages from '../messages';
import * as store from '../store'
import * as store from '../store';
let prevInput = [];
const backgroundStore = store.createStore(reducers, (e, sender) => {
console.error('Vim-Vixen:', e);
if (sender) {
@ -15,9 +16,9 @@ const backgroundStore = store.createStore(reducers, (e, sender) => {
}
});
backgroundStore.subscribe((sender) => {
let currentInput = backgroundStore.getState().input
let currentInput = backgroundStore.getState().input;
if (JSON.stringify(prevInput) === JSON.stringify(currentInput)) {
return
return;
}
prevInput = currentInput;
@ -39,13 +40,14 @@ backgroundStore.subscribe((sender) => {
const keyQueueChanged = (state, sender) => {
let prefix = keys.asKeymapChars(state.input.keys);
let matched = Object.keys(keys.defaultKeymap).filter((keys) => {
return keys.startsWith(prefix);
let matched = Object.keys(keys.defaultKeymap).filter((keyStr) => {
return keyStr.startsWith(prefix);
});
if (matched.length == 0) {
if (matched.length === 0) {
backgroundStore.dispatch(inputActions.clearKeys(), sender);
return Promise.resolve();
} else if (matched.length > 1 || matched.length === 1 && prefix !== matched[0]) {
} else if (matched.length > 1 ||
matched.length === 1 && prefix !== matched[0]) {
return Promise.resolve();
}
let action = keys.defaultKeymap[matched];
@ -56,15 +58,19 @@ const keyQueueChanged = (state, sender) => {
const handleMessage = (message, sender) => {
switch (message.type) {
case messages.KEYDOWN:
return backgroundStore.dispatch(inputActions.keyPress(message.code, message.ctrl), sender);
return backgroundStore.dispatch(
inputActions.keyPress(message.code, message.ctrl), sender);
case messages.CONSOLE_BLURRED:
return backgroundStore.dispatch(consoleActions.hide(), sender);
return backgroundStore.dispatch(
consoleActions.hide(), sender);
case messages.CONSOLE_ENTERED:
return backgroundStore.dispatch(commandActions.exec(message.text), sender);
return backgroundStore.dispatch(
commandActions.exec(message.text), sender);
case messages.CONSOLE_CHANGEED:
return backgroundStore.dispatch(commandActions.complete(message.text), sender);
return backgroundStore.dispatch(
commandActions.complete(message.text), sender);
}
}
};
browser.runtime.onMessage.addListener((message, sender) => {
try {

@ -30,28 +30,26 @@ const defaultKeymap = {
'F': { type: operations.FOLLOW_START, newTab: true },
'H': { type: operations.HISTORY_PREV },
'L': { type: operations.HISTORY_NEXT },
}
};
const asKeymapChars = (keys) => {
return keys.map((k) => {
let c = String.fromCharCode(k.code);
if (k.ctrl) {
return '<C-' + c.toUpperCase() + '>';
} else {
return c
}
return c;
}).join('');
}
};
const asCaretChars = (keys) => {
return keys.map((k) => {
let c = String.fromCharCode(k.code);
if (k.ctrl) {
return '^' + c.toUpperCase();
} else {
return c;
}
return c;
}).join('');
}
};
export { defaultKeymap, asKeymapChars, asCaretChars };

@ -12,9 +12,8 @@ const reopenTab = () => {
let session = sessions[0];
if (session.tab) {
return browser.sessions.restore(session.tab.sessionId);
} else {
return browser.sessions.restore(session.window.sessionId);
}
return browser.sessions.restore(session.window.sessionId);
});
};
@ -24,20 +23,20 @@ const selectAt = (index) => {
return;
}
if (index < 0 || tabs.length <= index) {
throw new RangeError(`tab ${index} does not exist`)
throw new RangeError(`tab ${index} does not exist`);
}
let id = tabs[index].id;
return browser.tabs.update(id, { active: true })
return browser.tabs.update(id, { active: true });
});
};
const selectByKeyword = (current, keyword) => {
return browser.tabs.query({ currentWindow: true }).then((tabs) => {
let matched = tabs.filter((t) => {
return t.url.includes(keyword) || t.title.includes(keyword)
})
return t.url.includes(keyword) || t.title.includes(keyword);
});
if (matched.length == 0) {
if (matched.length === 0) {
throw new RangeError('No matching buffer for ' + keyword);
}
for (let tab of matched) {
@ -47,13 +46,13 @@ const selectByKeyword = (current, keyword) => {
}
return browser.tabs.update(matched[0].id, { active: true });
});
}
};
const getCompletions = (keyword) => {
return browser.tabs.query({ currentWindow: true }).then((tabs) => {
let matched = tabs.filter((t) => {
return t.url.includes(keyword) || t.title.includes(keyword)
})
return t.url.includes(keyword) || t.title.includes(keyword);
});
return matched;
});
};
@ -63,9 +62,9 @@ const selectPrevTab = (current, count) => {
if (tabs.length < 2) {
return;
}
let select = (current - count) % tabs.length
let select = (current - count) % tabs.length;
let id = tabs[select].id;
return browser.tabs.update(id, { active: true })
return browser.tabs.update(id, { active: true });
});
};
@ -74,9 +73,9 @@ const selectNextTab = (current, count) => {
if (tabs.length < 2) {
return;
}
let select = (current + count + tabs.length) % tabs.length
let select = (current + count + tabs.length) % tabs.length;
let id = tabs[select].id;
return browser.tabs.update(id, { active: true })
return browser.tabs.update(id, { active: true });
});
};
@ -87,4 +86,7 @@ const reload = (current, cache) => {
);
};
export { closeTab, reopenTab, selectAt, selectByKeyword, getCompletions, selectPrevTab, selectNextTab, reload };
export {
closeTab, reopenTab, selectAt, selectByKeyword, getCompletions,
selectPrevTab, selectNextTab, reload
};

@ -3,15 +3,16 @@ export default class Completion {
if (typeof completions.length !== 'number') {
throw new TypeError('completions does not have a length in number');
}
this.completions = completions
this.completions = completions;
this.index = 0;
}
prev() {
if (this.completions.length === 0) {
let length = this.completions.length;
if (length === 0) {
return null;
}
this.index = (this.index + this.completions.length - 1) % this.completions.length
this.index = (this.index + length - 1) % length;
return this.completions[this.index];
}
@ -20,7 +21,7 @@ export default class Completion {
return null;
}
let item = this.completions[this.index];
this.index = (this.index + 1) % this.completions.length
this.index = (this.index + 1) % this.completions.length;
return item;
}
}

@ -3,10 +3,10 @@ import Completion from './completion';
import messages from '../messages';
// TODO consider object-oriented
var prevValue = "";
var completion = null;
var completionOrigin = "";
var prevState = {};
let prevValue = '';
let completion = null;
let completionOrigin = '';
let prevState = {};
const handleBlur = () => {
return browser.runtime.sendMessage({
@ -14,6 +14,20 @@ const handleBlur = () => {
});
};
const selectCompletion = (target) => {
let container = window.document.querySelector('#vimvixen-console-completion');
Array.prototype.forEach.call(container.children, (ele) => {
if (!ele.classList.contains('vimvixen-console-completion-item')) {
return;
}
if (ele === target) {
ele.classList.add('vimvixen-completion-selected');
} else {
ele.classList.remove('vimvixen-completion-selected');
}
});
};
const completeNext = () => {
if (!completion) {
return;
@ -27,7 +41,7 @@ const completeNext = () => {
input.value = completionOrigin + ' ' + item[0].content;
selectCompletion(item[1]);
}
};
const completePrev = () => {
if (!completion) {
@ -42,12 +56,12 @@ const completePrev = () => {
input.value = completionOrigin + ' ' + item[0].content;
selectCompletion(item[1]);
}
};
const handleKeydown = (e) => {
let input = window.document.querySelector('#vimvixen-console-command-input');
switch(e.keyCode) {
switch (e.keyCode) {
case KeyboardEvent.DOM_VK_ESCAPE:
return input.blur();
case KeyboardEvent.DOM_VK_RETURN:
@ -92,17 +106,17 @@ const createCompletionTitle = (text) => {
let li = document.createElement('li');
li.className = 'vimvixen-console-completion-title';
li.textContent = text;
return li
}
return li;
};
const createCompletionItem = (icon, caption, url) => {
let captionEle = document.createElement('span');
captionEle.className = 'vimvixen-console-completion-item-caption';
captionEle.textContent = caption
captionEle.textContent = caption;
let urlEle = document.createElement('span');
urlEle.className = 'vimvixen-console-completion-item-url';
urlEle.textContent = url
urlEle.textContent = url;
let li = document.createElement('li');
li.style.backgroundImage = 'url(' + icon + ')';
@ -110,24 +124,11 @@ const createCompletionItem = (icon, caption, url) => {
li.append(captionEle);
li.append(urlEle);
return li;
}
const selectCompletion = (target) => {
let container = window.document.querySelector('#vimvixen-console-completion');
Array.prototype.forEach.call(container.children, (ele) => {
if (!ele.classList.contains('vimvixen-console-completion-item')) {
return;
}
if (ele === target) {
ele.classList.add('vimvixen-completion-selected');
} else {
ele.classList.remove('vimvixen-completion-selected');
}
});
};
const updateCompletions = (completions) => {
let completionsContainer = window.document.querySelector('#vimvixen-console-completion');
let completionsContainer =
window.document.querySelector('#vimvixen-console-completion');
let input = window.document.querySelector('#vimvixen-console-command-input');
completionsContainer.innerHTML = '';
@ -148,7 +149,7 @@ const updateCompletions = (completions) => {
completion = new Completion(pairs);
completionOrigin = input.value.split(' ')[0];
}
};
const update = (state) => {
let error = window.document.querySelector('#vimvixen-console-error');
@ -163,12 +164,13 @@ const update = (state) => {
input.value = state.commandText;
input.focus();
}
if (JSON.stringify(state.completions) !== JSON.stringify(prevState.completions)) {
if (JSON.stringify(state.completions) !==
JSON.stringify(prevState.completions)) {
updateCompletions(state.completions);
}
prevState = state;
}
};
browser.runtime.onMessage.addListener((action) => {
if (action.type === messages.STATE_UPDATE) {

@ -8,11 +8,11 @@ const initialize = (doc) => {
doc.body.append(iframe);
return iframe;
}
};
const blur = (doc) => {
let iframe = doc.getElementById('vimvixen-console-frame');
iframe.blur();
}
};
export { initialize, blur };

@ -1,7 +1,7 @@
import Hint from './hint';
import HintKeyProducer from './hint-key-producer';
const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz'
const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz';
export default class Follow {
constructor(doc) {
@ -22,14 +22,14 @@ export default class Follow {
let producer = new HintKeyProducer(DEFAULT_HINT_CHARSET);
Array.prototype.forEach.call(elements, (ele) => {
let keys = producer.produce();
let hint = new Hint(ele, keys)
let hint = new Hint(ele, keys);
this.hintElements[keys] = hint;
});
}
handleKeydown(e) {
let keyCode = e.keyCode;
let { keyCode } = e;
if (keyCode === KeyboardEvent.DOM_VK_ESCAPE) {
this.remove();
return;
@ -56,10 +56,10 @@ export default class Follow {
let hidden = Object.keys(this.hintElements).filter((key) => {
return !key.startsWith(chars);
});
if (shown.length == 0) {
if (shown.length === 0) {
this.remove();
return;
} else if (shown.length == 1) {
} else if (shown.length === 1) {
this.remove();
this.hintElements[chars].activate();
}
@ -74,7 +74,7 @@ export default class Follow {
remove() {
this.doc.removeEventListener("keydown", this.boundKeydown);
this.doc.removeEventListener('keydown', this.boundKeydown);
Object.keys(this.hintElements).forEach((key) => {
this.hintElements[key].remove();
});
@ -87,6 +87,14 @@ export default class Follow {
);
}
static isNumericKey(code) {
return KeyboardEvent.DOM_VK_0 <= code && code <= KeyboardEvent.DOM_VK_9;
}
static isAlphabeticKey(code) {
return KeyboardEvent.DOM_VK_A <= code && code <= KeyboardEvent.DOM_VK_Z;
}
static codeChars(codes) {
const CHARCODE_ZERO = '0'.charCodeAt(0);
const CHARCODE_A = 'a'.charCodeAt(0);
@ -94,10 +102,12 @@ export default class Follow {
let chars = '';
for (let code of codes) {
if (KeyboardEvent.DOM_VK_0 <= code && code <= KeyboardEvent.DOM_VK_9) {
chars += String.fromCharCode(code - KeyboardEvent.DOM_VK_0 + CHARCODE_ZERO);
} else if (KeyboardEvent.DOM_VK_A <= code && code <= KeyboardEvent.DOM_VK_Z) {
chars += String.fromCharCode(code - KeyboardEvent.DOM_VK_A + CHARCODE_A);
if (Follow.isNumericKey(code)) {
chars += String.fromCharCode(
code - KeyboardEvent.DOM_VK_0 + CHARCODE_ZERO);
} else if (Follow.isAlphabeticKey(code)) {
chars += String.fromCharCode(
code - KeyboardEvent.DOM_VK_A + CHARCODE_A);
}
}
return chars;
@ -112,7 +122,7 @@ export default class Follow {
}
static isVisibleElement(element) {
var style = window.getComputedStyle(element);
let style = window.getComputedStyle(element);
if (style.display === 'none') {
return false;
} else if (style.visibility === 'hidden') {

@ -11,19 +11,19 @@ export default class HintKeyProducer {
produce() {
this.increment();
return this.counter.map((x) => this.charset[x]).join('');
return this.counter.map(x => this.charset[x]).join('');
}
increment() {
let max = this.charset.length - 1;
if (this.counter.every((x) => x == max)) {
if (this.counter.every(x => x === max)) {
this.counter = new Array(this.counter.length + 1).fill(0);
return;
}
this.counter.reverse();
let len = this.charset.length;
let num = this.counter.reduce((x,y,index) => x + y * (len ** index)) + 1;
let num = this.counter.reduce((x, y, index) => x + y * len ** index) + 1;
for (let i = 0; i < this.counter.length; ++i) {
this.counter[i] = num % len;
num = ~~(num / len);

@ -8,10 +8,9 @@ export default class Hint {
this.target = target;
let doc = target.ownerDocument
let doc = target.ownerDocument;
let { top, left } = target.getBoundingClientRect();
let scrollX = window.scrollX;
let scrollY = window.scrollY;
let { scrollX, scrollY } = window;
this.element = doc.createElement('span');
this.element.className = 'vimvixen-hint';

@ -1,8 +1,8 @@
const prev = (win) => {
win.history.back()
win.history.back();
};
const next = (win) => {
win.history.forward()
win.history.forward();
};
export { prev, next };

@ -4,11 +4,11 @@ import * as scrolls from '../content/scrolls';
import * as histories from '../content/histories';
import Follow from '../content/follow';
import operations from '../operations';
import messages from '../messages';
import messages from '../messages';
consoleFrames.initialize(window.document);
window.addEventListener("keypress", (e) => {
window.addEventListener('keypress', (e) => {
if (e.target instanceof HTMLInputElement) {
return;
}
@ -40,14 +40,14 @@ const execOperation = (operation) => {
case operations.HISTORY_NEXT:
return histories.next(window);
}
}
};
const update = (state) => {
if (!state.console.commandShown) {
window.focus();
consoleFrames.blur(window.document);
}
}
};
browser.runtime.onMessage.addListener((action) => {
switch (action.type) {

@ -37,4 +37,6 @@ const scrollRight = (page) => {
page.scrollTo(x, y);
};
export { scrollLines, scrollPages, scrollTop, scrollBottom, scrollLeft, scrollRight }
export {
scrollLines, scrollPages, scrollTop, scrollBottom, scrollLeft, scrollRight
};

@ -1,5 +1,5 @@
export default {
// command
// Command
COMMAND_OPEN: 'cmd.open',
COMMAND_TABS_OPEN: 'cmd.tabs.open',
COMMAND_BUFFER: 'cmd.buffer',
@ -14,7 +14,7 @@ export default {
HISTORY_PREV: 'history.prev',
HISTORY_NEXT: 'history.next',
// background
// Background
TABS_CLOSE: 'tabs.close',
TABS_REOPEN: 'tabs.reopen',
TABS_PREV: 'tabs.prev',
@ -23,4 +23,4 @@ export default {
ZOOM_IN: 'zoom.in',
ZOOM_OUT: 'zoom.out',
ZOOM_NEUTRAL: 'zoom.neutral',
}
};

@ -12,7 +12,7 @@ export default function reducer(state = defaultState, action = {}) {
switch (action.type) {
case actions.CONSOLE_SHOW_COMMAND:
return Object.assign({}, state, {
commandShown: true,
commandShown: true,
commandText: action.text,
errorShown: false,
completions: []

@ -8,10 +8,12 @@ export default function reducer(state = defaultState, action = {}) {
switch (action.type) {
case actions.INPUT_KEY_PRESS:
return Object.assign({}, state, {
keys: state.keys.concat([{
code: action.code,
ctrl: action.ctrl
}])
keys: state.keys.concat([
{
code: action.code,
ctrl: action.ctrl
}
])
});
case actions.INPUT_CLEAR_KEYS:
return Object.assign({}, state, {

@ -24,7 +24,7 @@ class Store {
this.catcher(e, sender);
}
}
return action
return action;
}
getState() {
@ -46,6 +46,8 @@ class Store {
const empty = () => {};
export function createStore(reducer, catcher = empty) {
const createStore = (reducer, catcher = empty) => {
return new Store(reducer, catcher);
}
};
export { createStore };