File: /var/www/zaklada/html/node_modules/node-haste/lib/loader/CSSLoader.js
/**
 * Copyright 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var inherits = require('util').inherits;
var zlib = require('zlib');
var docblock = require('../parse/docblock');
var ResourceLoader = require('./ResourceLoader');
var extractFBSprites = require('../parse/css').extractFBSprites;
var CSS = require('../resource/CSS');
var MessageList = require('../MessageList');
/**
 * @class Loads and parses CSS files
 * Extracts options from the docblock, calculates gziped network size. Network
 * size calculation is off by default due to it's perf cost. Use options
 * parameter to switch them on.
 *
 * @extends {ResourceLoader}
 * @param {Object|null} options Object with the following options:
 *                              - extractNetworkSize
 *                              - extractFBSprites
 */
function CSSLoader(options) {
  ResourceLoader.call(this, options);
  var extractNetworkSize = !!this.options.networkSize;
  if (extractNetworkSize) {
    this.extractExtra = this.extractNetworkSize;
  } else {
    this.extractExtra = function(css, sourceCode, messages, callback) {
      // make async to break long stack traces
      process.nextTick(function() {
        callback(messages, css);
      });
    };
  }
}
inherits(CSSLoader, ResourceLoader);
CSSLoader.prototype.path = __filename;
CSSLoader.prototype.getResourceTypes = function() {
  return [CSS];
};
CSSLoader.prototype.getExtensions = function() {
  return ['.css'];
};
/**
 * Extracts aproximate network size by gziping the source
 * @todo (voloko) why not minify?
 * Off by default due to perf cost
 *
 * @protected
 * @param  {CSS}   css
 * @param  {String}   sourceCode
 * @param  {Function} callback
 */
CSSLoader.prototype.extractNetworkSize =
  function(css, sourceCode, messages, callback) {
  zlib.deflate(sourceCode, function(err, buffer) {
    css.networkSize = buffer.length;
    callback(messages, css);
  });
};
/**
 * Initialize a resource with the source code and configuration
 * Loader can parse, gzip, minify the source code to build the resulting
 * Resource value object
 *
 * @protected
 * @param {String}               path      resource being built
 * @param {ProjectConfiguration} configuration configuration for the path
 * @param {String}               sourceCode
 * @param {Function}             callback
 */
CSSLoader.prototype.loadFromSource =
  function(path, configuration, sourceCode, messages, callback) {
  var css = new CSS(path);
  var props = docblock.parse(docblock.extract(sourceCode));
  props.forEach(function(pair) {
    var name = pair[0];
    var value = pair[1];
    switch (name) {
      case 'provides':
        css.id = value;
        break;
      case 'providesModule':
        css.isModule = true;
        css.id = 'css:' + value;
        break;
      case 'css':
        value.split(/\s+/).forEach(css.addRequiredCSS, css);
        break;
      case 'requires':
        value.split(/\s+/).forEach(css.addRequiredLegacyComponent, css);
        break;
      case 'nonblocking':
        css.isNonblocking = true;
        break;
      case 'nopackage':
        css.isNopackage = true;
        break;
      case 'permanent':
        css.isPermanent = true;
        break;
      case 'option':
      case 'options':
        value.split(/\s+/).forEach(function(key) {
          css.options[key] = true;
        });
        break;
      case 'author':
      case 'deprecated':
        // Support these so Diviner can pick them up.
        break;
      case 'nolint':
      case 'generated':
      case 'preserve-header':
        // various options
        break;
      case 'layer':
        // This directive is currently used by Connect JS library
        break;
      default:
        messages.addClowntownError(css.path, 'docblock',
          'Unknown directive ' + name);
    }
  });
  if (this.options.extractFBSprites) {
    css.fbSprites = extractFBSprites(sourceCode);
  }
  css.finalize();
  this.extractExtra(css, sourceCode, messages, callback);
};
/**
 * Only match *.css files
 * @param  {String} filePath
 * @return {Boolean}
 */
CSSLoader.prototype.matchPath = function(filePath) {
  return filePath.lastIndexOf('.css') === filePath.length - 4;
};
/**
 * Post process is called after the map is updated but before the update
 * task is complete.
 * Used to resolve local required paths and /index.js directory requires
 *
 * @param  {ResourceMap}      map
 * @param  {Array.<Resource>} resources
 * @param  {Function}         callback
 */
CSSLoader.prototype.postProcess = function(map, resources, callback) {
  var messages = MessageList.create();
  resources.forEach(function(r) {
    var resource, i, required;
    required = r.requiredCSS;
    for (i = 0; i < required.length; i++) {
      resource = map.getResource('CSS', 'css:' + required[i]);
      if (resource && resource.isModule) {
        required[i] = 'css:' + required[i];
      }
    }
  });
  process.nextTick(function() {
    callback(messages);
  });
};
module.exports = CSSLoader;