| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 | /*! * node-sass: lib/index.js */var path = require('path'),  clonedeep = require('lodash.clonedeep'),  assign = require('lodash.assign'),  sass = require('./extensions');/** * Require binding */var binding = require('./binding')(sass);/** * Get input file * * @param {Object} options * @api private */function getInputFile(options) {  return options.file ? path.resolve(options.file) : null;}/** * Get output file * * @param {Object} options * @api private */function getOutputFile(options) {  var outFile = options.outFile;  if (!outFile || typeof outFile !== 'string' || (!options.data && !options.file)) {    return null;  }  return path.resolve(outFile);}/** * Get source map * * @param {Object} options * @api private */function getSourceMap(options) {  var sourceMap = options.sourceMap;  if (sourceMap && typeof sourceMap !== 'string' && options.outFile) {    sourceMap = options.outFile + '.map';  }  return sourceMap && typeof sourceMap === 'string' ? path.resolve(sourceMap) : null;}/** * Get stats * * @param {Object} options * @api private */function getStats(options) {  var stats = {};  stats.entry = options.file || 'data';  stats.start = Date.now();  return stats;}/** * End stats * * @param {Object} stats * @param {Object} sourceMap * @api private */function endStats(stats) {  stats.end = Date.now();  stats.duration = stats.end - stats.start;  return stats;}/** * Get style * * @param {Object} options * @api private */function getStyle(options) {  var styles = {    nested: 0,    expanded: 1,    compact: 2,    compressed: 3  };  return styles[options.outputStyle] || 0;}/** * Get indent width * * @param {Object} options * @api private */function getIndentWidth(options) {  var width = parseInt(options.indentWidth) || 2;  return width > 10 ? 2 : width;}/** * Get indent type * * @param {Object} options * @api private */function getIndentType(options) {  var types = {    space: 0,    tab: 1  };  return types[options.indentType] || 0;}/** * Get linefeed * * @param {Object} options * @api private */function getLinefeed(options) {  var feeds = {    cr: '\r',    crlf: '\r\n',    lf: '\n',    lfcr: '\n\r'  };  return feeds[options.linefeed] || '\n';}/** * Build an includePaths string * from the options.includePaths array and the SASS_PATH environment variable * * @param {Object} options * @api private */function buildIncludePaths(options) {  options.includePaths = options.includePaths || [];  if (process.env.hasOwnProperty('SASS_PATH')) {    options.includePaths = options.includePaths.concat(      process.env.SASS_PATH.split(path.delimiter)    );  }  return options.includePaths.join(path.delimiter);}/** * Get options * * @param {Object} options * @api private */function getOptions(opts, cb) {  if (typeof opts !== 'object') {    throw new Error('Invalid: options is not an object.');  }  var options = clonedeep(opts || {});  options.sourceComments = options.sourceComments || false;  if (options.hasOwnProperty('file')) {    options.file = getInputFile(options);  }  options.outFile = getOutputFile(options);  options.includePaths = buildIncludePaths(options);  options.precision = parseInt(options.precision) || 5;  options.sourceMap = getSourceMap(options);  options.style = getStyle(options);  options.indentWidth = getIndentWidth(options);  options.indentType = getIndentType(options);  options.linefeed = getLinefeed(options);  // context object represents node-sass environment  options.context = { options: options, callback: cb };  options.result = {    stats: getStats(options)  };  return options;}/** * Executes a callback and transforms any exception raised into a sass error * * @param {Function} callback * @param {Array} arguments * @api private */function tryCallback(callback, args) {  try {    return callback.apply(this, args);  } catch (e) {    if (typeof e === 'string') {      return new binding.types.Error(e);    } else if (e instanceof Error) {      return new binding.types.Error(e.message);    } else {      return new binding.types.Error('An unexpected error occurred');    }  }}/** * Normalizes the signature of custom functions to make it possible to just supply the * function name and have the signature default to `fn(...)`. The callback is adjusted * to transform the input sass list into discrete arguments. * * @param {String} signature * @param {Function} callback * @return {Object} * @api private */function normalizeFunctionSignature(signature, callback) {  if (!/^\*|@warn|@error|@debug|\w+\(.*\)$/.test(signature)) {    if (!/\w+/.test(signature)) {      throw new Error('Invalid function signature format "' + signature + '"');    }    return {      signature: signature + '(...)',      callback: function() {        var args = Array.prototype.slice.call(arguments),          list = args.shift(),          i;        for (i = list.getLength() - 1; i >= 0; i--) {          args.unshift(list.getValue(i));        }        return callback.apply(this, args);      }    };  }  return {    signature: signature,    callback: callback  };}/** * Render * * @param {Object} options * @api public */module.exports.render = function(opts, cb) {  var options = getOptions(opts, cb);  // options.error and options.success are for libsass binding  options.error = function(err) {    var payload = assign(new Error(), JSON.parse(err));    if (cb) {      options.context.callback.call(options.context, payload, null);    }  };  options.success = function() {    var result = options.result;    var stats = endStats(result.stats);    var payload = {      css: result.css,      map: result.map,      stats: stats    };    if (cb) {      options.context.callback.call(options.context, null, payload);    }  };  var importer = options.importer;  if (importer) {    if (Array.isArray(importer)) {      options.importer = [];      importer.forEach(function(subject, index) {        options.importer[index] = function(file, prev, bridge) {          function done(result) {            bridge.success(result === module.exports.NULL ? null : result);          }          var result = subject.call(options.context, file, prev, done);          if (result !== undefined) {            done(result);          }        };      });    } else {      options.importer = function(file, prev, bridge) {        function done(result) {          bridge.success(result === module.exports.NULL ? null : result);        }        var result = importer.call(options.context, file, prev, done);        if (result !== undefined) {          done(result);        }      };    }  }  var functions = clonedeep(options.functions);  if (functions) {    options.functions = {};    Object.keys(functions).forEach(function(subject) {      var cb = normalizeFunctionSignature(subject, functions[subject]);      options.functions[cb.signature] = function() {        var args = Array.prototype.slice.call(arguments),          bridge = args.pop();        function done(data) {          bridge.success(data);        }        var result = tryCallback(cb.callback.bind(options.context), args.concat(done));        if (result) {          done(result);        }      };    });  }  if (options.data) {    binding.render(options);  } else if (options.file) {    binding.renderFile(options);  } else {    cb({status: 3, message: 'No input specified: provide a file name or a source string to process' });  }};/** * Render sync * * @param {Object} options * @api public */module.exports.renderSync = function(opts) {  var options = getOptions(opts);  var importer = options.importer;  if (importer) {    if (Array.isArray(importer)) {      options.importer = [];      importer.forEach(function(subject, index) {        options.importer[index] = function(file, prev) {          var result = subject.call(options.context, file, prev);          return result === module.exports.NULL ? null : result;        };      });    } else {      options.importer = function(file, prev) {        var result = importer.call(options.context, file, prev);        return result === module.exports.NULL ? null : result;      };    }  }  var functions = clonedeep(options.functions);  if (options.functions) {    options.functions = {};    Object.keys(functions).forEach(function(signature) {      var cb = normalizeFunctionSignature(signature, functions[signature]);      options.functions[cb.signature] = function() {        return tryCallback(cb.callback.bind(options.context), arguments);      };    });  }  var status;  if (options.data) {    status = binding.renderSync(options);  } else if (options.file) {    status = binding.renderFileSync(options);  } else {    throw new Error('No input specified: provide a file name or a source string to process');  }  var result = options.result;  if (status) {    result.stats = endStats(result.stats);    return result;  }  throw assign(new Error(), JSON.parse(result.error));};/** * API Info * * @api public */module.exports.info = sass.getVersionInfo(binding);/** * Expose sass types */module.exports.types = binding.types;module.exports.TRUE = binding.types.Boolean.TRUE;module.exports.FALSE = binding.types.Boolean.FALSE;module.exports.NULL = binding.types.Null.NULL;/** * Polyfill the old API * * TODO: remove for 4.0 */function processSassDeprecationMessage() {  console.log('Deprecation warning: `process.sass` is an undocumented internal that will be removed in future versions of Node Sass.');}process.sass = process.sass || {  get versionInfo()   { processSassDeprecationMessage(); return module.exports.info; },  get binaryName()    { processSassDeprecationMessage(); return sass.getBinaryName(); },  get binaryUrl()     { processSassDeprecationMessage(); return sass.getBinaryUrl(); },  get binaryPath()    { processSassDeprecationMessage(); return sass.getBinaryPath(); },  get getBinaryPath() { processSassDeprecationMessage(); return sass.getBinaryPath; },};
 |