From 0652131de885df3ebb7c9c0e762fd1604486a892 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sat, 21 Jul 2018 15:59:30 +0900
Subject: Clean and tests for filters on open command

---
 src/background/repositories/completions.js | 81 +-----------------------------
 src/background/usecases/completions.js     | 12 +++++
 src/background/usecases/filters.js         | 72 ++++++++++++++++++++++++++
 3 files changed, 86 insertions(+), 79 deletions(-)
 create mode 100644 src/background/usecases/filters.js

(limited to 'src/background')

diff --git a/src/background/repositories/completions.js b/src/background/repositories/completions.js
index c4e956e..1318d36 100644
--- a/src/background/repositories/completions.js
+++ b/src/background/repositories/completions.js
@@ -12,88 +12,11 @@ export default class CompletionsRepository {
     });
   }
 
-  // eslint-disable-next-line complexity, max-lines-per-function
-  async queryHistories(keywords) {
-    const filterHttp = (items) => {
-      const httpsHosts = items
-        .filter(item => item[1].protocol === 'https:')
-        .map(item => item[1].host);
-      const httpsHostSet = new Set(httpsHosts);
-      return items.filter(
-        item => !(item[1].protocol === 'http:' &&
-          httpsHostSet.has(item[1].host))
-      );
-    };
-
-    const filterEmptyTitle = (items) => {
-      return items.filter(item => item[0].title && item[0].title !== '');
-    };
-
-    const filterClosedPath = (items) => {
-      const allSimplePaths = items
-        .filter(item => item[1].hash === '' && item[1].search === '')
-        .map(item => item[1].origin + item[1].pathname);
-      const allSimplePathSet = new Set(allSimplePaths);
-      return items.filter(
-        item => !(item[1].hash === '' && item[1].search === '' &&
-          (/\/$/).test(item[1].pathname) &&
-          allSimplePathSet.has(
-            (item[1].origin + item[1].pathname).replace(/\/$/, '')
-          )
-        )
-      );
-    };
-
-    const reduceByPathname = (items, min) => {
-      let hash = {};
-      for (let item of items) {
-        let pathname = item[1].origin + item[1].pathname;
-        if (!hash[pathname]) {
-          hash[pathname] = item;
-        } else if (hash[pathname][1].href.length > item[1].href.length) {
-          hash[pathname] = item;
-        }
-      }
-      let filtered = Object.values(hash);
-      if (filtered.length < min) {
-        return items;
-      }
-      return filtered;
-    };
-
-    const reduceByOrigin = (items, min) => {
-      let hash = {};
-      for (let item of items) {
-        let origin = item[1].origin;
-        if (!hash[origin]) {
-          hash[origin] = item;
-        } else if (hash[origin][1].href.length > item[1].href.length) {
-          hash[origin] = item;
-        }
-      }
-      let filtered = Object.values(hash);
-      if (filtered.length < min) {
-        return items;
-      }
-      return filtered;
-    };
-
-
-    let historyItems = await browser.history.search({
+  queryHistories(keywords) {
+    return browser.history.search({
       text: keywords,
       startTime: 0,
     });
-    return [historyItems.map(item => [item, new URL(item.url)])]
-      .map(filterEmptyTitle)
-      .map(filterHttp)
-      .map(filterClosedPath)
-      .map(items => reduceByPathname(items, 10))
-      .map(items => reduceByOrigin(items, 10))
-      .map(items => items
-        .sort((x, y) => x[0].visitCount < y[0].visitCount)
-        .slice(0, 10)
-        .map(item => item[0])
-      )[0];
   }
 
   async queryTabs(keywords, excludePinned) {
diff --git a/src/background/usecases/completions.js b/src/background/usecases/completions.js
index 0bc34d1..1c0fe38 100644
--- a/src/background/usecases/completions.js
+++ b/src/background/usecases/completions.js
@@ -3,6 +3,9 @@ import CompletionGroup from '../domains/completion-group';
 import Completions from '../domains/completions';
 import CompletionRepository from '../repositories/completions';
 import CommandDocs from 'background/shared/commands/docs';
+import * as filters from './filters';
+
+const COMPLETION_ITEM_LIMIT = 10;
 
 export default class CompletionsInteractor {
   constructor() {
@@ -28,9 +31,18 @@ export default class CompletionsInteractor {
   }
 
   async queryOpen(name, keywords) {
+    // TODO get search engines from settings
     let groups = [];
     let histories = await this.completionRepository.queryHistories(keywords);
     if (histories.length > 0) {
+      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);
       let items = histories.map(page => new CompletionItem({
         caption: page.title,
         content: name + ' ' + page.url,
diff --git a/src/background/usecases/filters.js b/src/background/usecases/filters.js
new file mode 100644
index 0000000..d057dca
--- /dev/null
+++ b/src/background/usecases/filters.js
@@ -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
+};
-- 
cgit v1.2.3