Repository: projectwallace/css-analyzer (js)

Issue:
Add top identifier count analysis
It is already possible to see the top identifier selectors, but it would be nice to have direct access to the top identifier count directly instead of having to get that from another metric.

Pull request description:
add max identifier count analysis
it's easier to get the max identifier count from a simple object than havingto get it from an array

this also solidifies naming conventions for count/value instead of some metric-specific names.

closes #52 

Patch:
diff --git a/src/analyzer/selectors/identifiers.js b/src/analyzer/selectors/identifiers.js
index 2967f3d..61c0c65 100644
--- a/src/analyzer/selectors/identifiers.js
+++ b/src/analyzer/selectors/identifiers.js
@@ -1,37 +1,42 @@
 const specificity = require('specificity')
 const {caseInsensitive: stringCompare} = require('string-natural-compare')
 
+// Sort by identifiers count, then by alphabet
+function sortByIdentifiersCount(a, b) {
+  if (a.count === b.count) {
+    return stringCompare(a, b)
+  }
+
+  return b.count - a.count
+}
+
+function getSelectorSpecificity(selector) {
+  return specificity.calculate(selector).shift()
+}
+
 module.exports = selectors => {
-  const totalSelectors = selectors.length
   const identifiersPerSelector = selectors
-    .map(selector => specificity.calculate(selector).shift())
-    .map(selector => {
+    .map(getSelectorSpecificity)
+    .map(specificity => {
       return {
-        selector: selector.selector,
-        identifiers: selector.parts.length
+        value: specificity.selector,
+        count: specificity.parts.length
       }
     })
 
   const totalIdentifiers = identifiersPerSelector
-    .map(selector => selector.identifiers)
+    .map(selector => selector.count)
     .reduce((prev, curr) => prev + curr, 0)
-  const average = totalIdentifiers / totalSelectors
-
-  const top = count => {
-    // Sort by identifiers count, then by alphabet
-    const sorter = (a, b) => {
-      if (a.identifiers === b.identifiers) {
-        return stringCompare(a, b)
-      }
 
-      return b.identifiers - a.identifiers
-    }
+  const totalSelectors = selectors.length
+  const average = totalIdentifiers / totalSelectors
 
-    return identifiersPerSelector.sort(sorter).slice(0, count)
-  }
+  const sorted = identifiersPerSelector.sort(sortByIdentifiersCount)
+  const [max] = sorted
 
   return {
     average,
-    top: top(5)
+    max,
+    top: sorted.slice(0, 5)
   }
 }
diff --git a/src/analyzer/selectors/specificity.js b/src/analyzer/selectors/specificity.js
index 1e95c1b..0740707 100644
--- a/src/analyzer/selectors/specificity.js
+++ b/src/analyzer/selectors/specificity.js
@@ -7,24 +7,21 @@ module.exports = selectors => {
     .reverse()
 
   const top = count => {
-    return [...all]
-      .slice(0, count)
-      .map(selector => {
-        const spec = specificity
-          .calculate(selector)
-          .shift()
-          .specificityArray
+    return [...all].slice(0, count).map(selector => {
+      const [a, b, c, d] = specificity
+        .calculate(selector)
+        .shift().specificityArray
 
-        return {
-          selector,
-          specificity: {
-            a: spec[0],
-            b: spec[1],
-            c: spec[2],
-            d: spec[3]
-          }
+      return {
+        value: selector,
+        specificity: {
+          a,
+          b,
+          c,
+          d
         }
-      })
+      }
+    })
   }
 
   return {


Test patch:
diff --git a/test/analyzer/index.js b/test/analyzer/index.js
index 56b5e70..09a16c5 100644
--- a/test/analyzer/index.js
+++ b/test/analyzer/index.js
@@ -68,12 +68,14 @@ test('Returns the correct analysis object structure', async t => {
     'selectors.id.totalUnique': 0,
     'selectors.id.unique': [],
     'selectors.identifiers.average': 1,
-    'selectors.identifiers.top': [{identifiers: 1, selector: 'foo'}],
+    'selectors.identifiers.top': [{count: 1, value: 'foo'}],
+    'selectors.identifiers.max.count': 1,
+    'selectors.identifiers.max.value': 'foo',
     'selectors.js.total': 0,
     'selectors.js.totalUnique': 0,
     'selectors.js.unique': [],
     'selectors.specificity.top': [
-      {selector: 'foo', specificity: {a: 0, b: 0, c: 0, d: 1}}
+      {value: 'foo', specificity: {a: 0, b: 0, c: 0, d: 1}}
     ],
     'selectors.total': 1,
     'selectors.totalUnique': 1,
diff --git a/test/analyzer/selectors/output.json b/test/analyzer/selectors/output.json
index 3a6f6a6..ec9c69c 100644
--- a/test/analyzer/selectors/output.json
+++ b/test/analyzer/selectors/output.json
@@ -108,7 +108,7 @@
   "specificity": {
     "top": [
       {
-        "selector": ".Foo > .Bar ~ .Baz [type=\"text\"] + span:before #bazz #fizz #buzz #drank #drugs",
+        "value": ".Foo > .Bar ~ .Baz [type=\"text\"] + span:before #bazz #fizz #buzz #drank #drugs",
         "specificity": {
           "a": 0,
           "b": 5,
@@ -117,7 +117,7 @@
         }
       },
       {
-        "selector": "#multipe #ids #counted #as #one",
+        "value": "#multipe #ids #counted #as #one",
         "specificity": {
           "a": 0,
           "b": 5,
@@ -126,7 +126,7 @@
         }
       },
       {
-        "selector": "#foo",
+        "value": "#foo",
         "specificity": {
           "a": 0,
           "b": 1,
@@ -135,7 +135,7 @@
         }
       },
       {
-        "selector": "#jsSelector",
+        "value": "#jsSelector",
         "specificity": {
           "a": 0,
           "b": 1,
@@ -144,7 +144,7 @@
         }
       },
       {
-        "selector": ".a .b .c .d .e .f .g .h .i .j .k .l .m .n .o .p .q .r .s .t .u .v .w .x .y .z",
+        "value": ".a .b .c .d .e .f .g .h .i .j .k .l .m .n .o .p .q .r .s .t .u .v .w .x .y .z",
         "specificity": {
           "a": 0,
           "b": 0,
@@ -156,26 +156,30 @@
   },
   "identifiers": {
     "average": 2.8461538461538463,
+    "max": {
+      "count": 26,
+      "value": ".a .b .c .d .e .f .g .h .i .j .k .l .m .n .o .p .q .r .s .t .u .v .w .x .y .z"
+    },
     "top": [
       {
-        "identifiers": 26,
-        "selector": ".a .b .c .d .e .f .g .h .i .j .k .l .m .n .o .p .q .r .s .t .u .v .w .x .y .z"
+        "count": 26,
+        "value": ".a .b .c .d .e .f .g .h .i .j .k .l .m .n .o .p .q .r .s .t .u .v .w .x .y .z"
       },
       {
-        "identifiers": 11,
-        "selector": ".Foo > .Bar ~ .Baz [type=\"text\"] + span:before #bazz #fizz #buzz #drank #drugs"
+        "count": 11,
+        "value": ".Foo > .Bar ~ .Baz [type=\"text\"] + span:before #bazz #fizz #buzz #drank #drugs"
       },
       {
-        "identifiers": 5,
-        "selector": "#multipe #ids #counted #as #one"
+        "count": 5,
+        "value": "#multipe #ids #counted #as #one"
       },
       {
-        "identifiers": 3,
-        "selector": "[role=\"menuitem\"][aria-checked=\"true\"]::before"
+        "count": 3,
+        "value": "[role=\"menuitem\"][aria-checked=\"true\"]::before"
       },
       {
-        "identifiers": 2,
-        "selector": "* html .selector"
+        "count": 2,
+        "value": "* html .selector"
       }
     ]
   },