all files / src/ index.js

100% Statements 72/72
95.83% Branches 23/24
87.5% Functions 7/8
100% Lines 35/35
2 statements, 2 branches Ignored     
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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83                                          23× 23× 23× 23× 23× 23×   23×   23×                 39×   39×         39× 39×     38× 38×   38×     38×     38× 38×   38×     38×      
import debug from 'debug';
import hook from './hook';
import identity from 'lodash.identity';
import extractor from './extractor';
import { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
import { removeQuotes } from './utility';
import validate from './validate';
import './guard';
 
// cache
let tokensByFile = {};
// global
let instance = extractor({}, fetch);
let processorOptions = {};
let preProcess = identity;
let postProcess;
 
const debugFetch = debug('css-modules:fetch');
const debugSetup = debug('css-modules:setup');
 
/**
 * @param  {array}    options.extensions
 * @param  {function} options.preprocessCss
 * @param  {function} options.processCss
 * @param  {string}   options.to
 * @param  {object}   options.rest
 */
export default function setup({ extensions: extraExtensions, preprocessCss, processCss, to, ...rest } = {}) {
  debugSetup(arguments[0]);
  validate(arguments[0]);
  instance = extractor(rest, fetch);
  processorOptions = {to};
  preProcess = preprocessCss || identity;
  postProcess = processCss || null;
  // clearing cache
  tokensByFile = {};
 
  if (extraExtensions) {
    extraExtensions.forEach((extension) => hook(filename => fetch(filename, filename), extension));
  }
}
 
/**
 * @param  {string} _to  Absolute or relative path. Also can be path to the Node.JS module.
 * @param  {string} from Absolute path.
 * @return {object}
 */
function fetch(_to, from) {
  const to = removeQuotes(_to);
  // getting absolute path to the processing file
  const filename = /\w/i.test(to[0])
    ? require.resolve(to)
    : resolve(dirname(from), to);
 
  // checking cache
  let tokens = tokensByFile[filename];
  if (tokens) {
    debugFetch({cache: true, filename});
    return tokens;
  }
 
  debugFetch({cache: false, filename});
  const CSSSource = preProcess(readFileSync(filename, 'utf8'), filename);
  // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts
  const lazyResult = instance.process(CSSSource, Object.assign(processorOptions, {from: filename}));
 
  // https://github.com/postcss/postcss/blob/master/docs/api.md#lazywarnings
  lazyResult.warnings().forEach(message => console.warn(message.text));
 
  // updating cache
  tokens = lazyResult.root.tokens;
  tokensByFile[filename] = tokens;
 
  if (postProcess) {
    postProcess(lazyResult.css, filename);
  }
 
  return tokens;
}
 
hook(filename => fetch(filename, filename), '.css');