all files / src/ count.js

55.17% Statements 16/29
66.67% Branches 10/15
30% Functions 3/10
53.57% Lines 15/28
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68    24×     196×       80×                 86×     22×                                                                        
/* eslint no-use-before-define: 0 */
import fsp from 'fs-promise';
import css from 'css';
import { SELECTOR_LIMIT } from './constants';
import { expand } from './fs-utils';
 
function count(ast) {
  function countRules(rules) {
    return rules.reduce((acc, rule) => acc + count(rule), 0);
  }
 
  switch (ast.type) {
    case 'stylesheet':
      return countRules(ast.stylesheet.rules);
    case 'rule':
      return ast.selectors.length;
    // Don't affect selector limit
    case 'comment':
    case 'font-face':
    case 'keyframes':
    case 'import':
    case 'supports':
    case 'charset':
    case 'namespace':
      return 0;
    case 'page':
      return 1;
    default:
      return countRules(ast.rules);
  }
}
 
function countFile(filepath, options) {
  return fsp.readFile(filepath, { encoding: 'utf8' })
    .then(contents => {
      let ast = css.parse(contents);
      let selectorCount = count(ast);
 
      return {
        filepath,
        selectorCount,
        exceedsLimit: selectorCount > SELECTOR_LIMIT
      };
    });
}
 
function countPath(filepath, options) {
  options = options || {};
 
  return expand(filepath)
    .filter(x => /\.css$/.test(x))
    .map(x => countFile(x, options))
    .flatMap(x => {
      if (options.progress) {
        options.progress(x.filepath);
      }
 
      return x;
    })
    .reduce((acc, x) => acc.concat([x]), [])
    .toPromise(Promise);
}
 
export default {
  count,
  countPath
};