From ddce6433dc82b3028c55ebb051e43e396ff14cb6 Mon Sep 17 00:00:00 2001
From: Haroen Viaene <hello@haroen.me>
Date: Tue, 6 Aug 2019 16:54:54 +0200
Subject: [PATCH] feat(formatPkg): add .js to alternative names

fixes #217

1. split out getAlternativeNames
2. avoid duplicates in getAlternativeNames
3. no longer put concatenatedName in _searchInternal (not relied upon)
4. add .js or non-.js name
5. small prettier fix
6. update readme
---
 README.md                                     |  4 +-
 .../__snapshots__/formatPkg.test.js.snap      | 12 ++-
 src/__tests__/formatPkg.test.js               | 74 +++++++++++++++++--
 src/formatPkg.js                              | 22 +++++-
 4 files changed, 95 insertions(+), 17 deletions(-)

diff --git a/README.md b/README.md
index 00cc977f4..75675c38e 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,6 @@ For every single NPM package, we create a record in the Algolia index. The resul
 ```json5
 {
   name: 'babel-core',
-  concatenatedName: 'babelcore',
   downloadsLast30Days: 10978749,
   downloadsRatio: 0.08310651682685861,
   humanDownloadsLast30Days: '11m',
@@ -129,6 +128,9 @@ For every single NPM package, we create a record in the Algolia index. The resul
     popularName: 'babel-core',
     downloadsMagnitude: 8,
     jsDelivrPopularity: 5,
+    alternativeNames: [
+      // alternative versions of this name, to show up on confused searches
+    ],
   },
 }
 ```
diff --git a/src/__tests__/__snapshots__/formatPkg.test.js.snap b/src/__tests__/__snapshots__/formatPkg.test.js.snap
index 88d39b9be..08c2e4d8c 100644
--- a/src/__tests__/__snapshots__/formatPkg.test.js.snap
+++ b/src/__tests__/__snapshots__/formatPkg.test.js.snap
@@ -6,9 +6,9 @@ Object {
     "alternativeNames": Array [
       "atlaskitinput",
       " atlaskit input",
+      "@atlaskit/input.js",
       "@atlaskit/input",
     ],
-    "concatenatedName": "atlaskitinput",
   },
   "bin": undefined,
   "computedKeywords": Array [],
@@ -201,9 +201,9 @@ Object {
     "alternativeNames": Array [
       "atomicpackagetab",
       " atomic package tab",
+      "@atomic-package/tab.js",
       "@atomic-package/tab",
     ],
-    "concatenatedName": "atomicpackagetab",
   },
   "bin": undefined,
   "computedKeywords": Array [],
@@ -314,9 +314,9 @@ Object {
     "alternativeNames": Array [
       "createinstantsearchapp",
       "create instantsearch app",
+      "create-instantsearch-app.js",
       "create-instantsearch-app",
     ],
-    "concatenatedName": "createinstantsearchapp",
   },
   "bin": Object {
     "create-instantsearch-app": "src/cli/index.js",
@@ -431,10 +431,8 @@ Object {
   "_searchInternal": Object {
     "alternativeNames": Array [
       "indexof",
-      "indexof",
-      "indexof",
+      "indexof.js",
     ],
-    "concatenatedName": "indexof",
   },
   "bin": undefined,
   "computedKeywords": Array [],
@@ -515,9 +513,9 @@ Object {
     "alternativeNames": Array [
       "longboy",
       "long boy",
+      "long-boy.js",
       "long-boy",
     ],
-    "concatenatedName": "longboy",
   },
   "bin": undefined,
   "computedKeywords": Array [],
diff --git a/src/__tests__/formatPkg.test.js b/src/__tests__/formatPkg.test.js
index 5395ef209..0bbcb634d 100644
--- a/src/__tests__/formatPkg.test.js
+++ b/src/__tests__/formatPkg.test.js
@@ -25,10 +25,10 @@ it('keeps .bin intact', () => {
   );
   const formatted = formatPkg(createInstantSearchApp);
   expect(formatted.bin).toMatchInlineSnapshot(`
-Object {
-  "create-instantsearch-app": "src/cli/index.js",
-}
-`);
+        Object {
+          "create-instantsearch-app": "src/cli/index.js",
+        }
+    `);
 });
 
 it('truncates long readmes', () => {
@@ -223,7 +223,7 @@ describe('adds TypeScript information', () => {
   });
 });
 
-describe('test getRepositoryInfo', () => {
+describe('getRepositoryInfo', () => {
   const getRepositoryInfo = formatPkg.__RewireAPI__.__get__(
     'getRepositoryInfo'
   );
@@ -377,3 +377,67 @@ describe('test getRepositoryInfo', () => {
     expect(getRepositoryInfo('aaaaaaaa')).toBe(null);
   });
 });
+
+describe('alternative names', () => {
+  test('name not yet ending in .js', () => {
+    const original = {
+      name: 'places',
+      lastPublisher: { name: 'unknown' },
+    };
+    expect(formatPkg(original)._searchInternal.alternativeNames)
+      .toMatchInlineSnapshot(`
+      Array [
+        "places",
+        "places.js",
+      ]
+    `);
+  });
+
+  test('name ending in .js', () => {
+    const original = {
+      name: 'places.js',
+      lastPublisher: { name: 'unknown' },
+    };
+    expect(formatPkg(original)._searchInternal.alternativeNames)
+      .toMatchInlineSnapshot(`
+            Array [
+              "placesjs",
+              "places js",
+              "places",
+              "places.js",
+            ]
+        `);
+  });
+
+  test('scoped package', () => {
+    const original = {
+      name: '@algolia/places.js',
+      lastPublisher: { name: 'unknown' },
+    };
+    expect(formatPkg(original)._searchInternal.alternativeNames)
+      .toMatchInlineSnapshot(`
+            Array [
+              "algoliaplacesjs",
+              " algolia places js",
+              "@algolia/places",
+              "@algolia/places.js",
+            ]
+        `);
+  });
+
+  test('name with - and _', () => {
+    const original = {
+      name: 'this-is_a-dumb-name',
+      lastPublisher: { name: 'unknown' },
+    };
+    expect(formatPkg(original)._searchInternal.alternativeNames)
+      .toMatchInlineSnapshot(`
+      Array [
+        "thisisadumbname",
+        "this is a dumb name",
+        "this-is_a-dumb-name.js",
+        "this-is_a-dumb-name",
+      ]
+    `);
+  });
+});
diff --git a/src/formatPkg.js b/src/formatPkg.js
index 5a8becb7e..a5962cfba 100644
--- a/src/formatPkg.js
+++ b/src/formatPkg.js
@@ -59,8 +59,7 @@ export default function formatPkg(pkg) {
 
   const dependencies = cleaned.dependencies || {};
   const devDependencies = cleaned.devDependencies || {};
-  const concatenatedName = cleaned.name.replace(/[-/@_.]+/g, '');
-  const splitName = cleaned.name.replace(/[-/@_.]+/g, ' ');
+  const alternativeNames = getAlternativeNames(cleaned.name);
 
   const tags = pkg['dist-tags'];
 
@@ -97,8 +96,7 @@ export default function formatPkg(pkg) {
     types,
     lastCrawl: new Date().toISOString(),
     _searchInternal: {
-      concatenatedName,
-      alternativeNames: [concatenatedName, splitName, cleaned.name],
+      alternativeNames,
     },
   };
 
@@ -417,3 +415,19 @@ function getTypes(pkg) {
     ts: false,
   };
 }
+
+/**
+ * @param {string} name
+ */
+function getAlternativeNames(name) {
+  const concatenatedName = name.replace(/[-/@_.]+/g, '');
+  const splitName = name.replace(/[-/@_.]+/g, ' ');
+  const dotJSName = name.endsWith('.js')
+    ? name.substring(0, name.length - 3)
+    : `${name}.js`;
+  const normalName = name;
+
+  return Array.from(
+    new Set([concatenatedName, splitName, dotJSName, normalName])
+  );
+}