text: 'use strict';
  
  var fs = require('fs');
  var path = require('path');
  var define = require('define-property');
  var sourceMapResolve = require('source-map-resolve');
  var SourceMap = require('source-map');
  
  /**
   * Expose `mixin()`.
   * This code is based on `source-maps-support.js` in reworkcss/css
   * https://github.com/reworkcss/css/blob/master/lib/stringify/source-map-support.js
   * Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
   */
  
  module.exports = mixin;
  
  /**
   * Mixin source map support into `compiler`.
   *
   * @param {Object} `compiler`
   * @api public
   */
  
  function mixin(compiler) {
    define(compiler, '_comment', compiler.comment);
    compiler.map = new SourceMap.SourceMapGenerator();
    compiler.position = { line: 1, column: 1 };
    compiler.content = {};
    compiler.files = {};
  
    for (var key in exports) {
      define(compiler, key, exports[key]);
    }
  }
  
  /**
   * Update position.
   *
   * @param {String} str
   */
  
  exports.updatePosition = function(str) {
    var lines = str.match(/\n/g);
    if (lines) this.position.line += lines.length;
    var i = str.lastIndexOf('\n');
    this.position.column = ~i ? str.length - i : this.position.column + str.length;
  };
  
  /**
   * Emit `str` with `position`.
   *
   * @param {String} str
   * @param {Object} [pos]
   * @return {String}
   */
  
  exports.emit = function(str, node) {
    var position = node.position || {};
    var source = position.source;
    if (source) {
      if (position.filepath) {
        source = unixify(position.filepath);
      }
  
      this.map.addMapping({
        source: source,
        generated: {
          line: this.position.line,
          column: Math.max(this.position.column - 1, 0)
        },
        original: {
          line: position.start.line,
          column: position.start.column - 1
        }
      });
  
      if (position.content) {
        this.addContent(source, position);
      }
      if (position.filepath) {
        this.addFile(source, position);
      }
    }
  
    this.updatePosition(str);
    this.output += str;
    return str;
  };
  
  /**
   * Adds a file to the source map output if it has not already been added
   * @param {String} `file`
   * @param {Object} `pos`
   */
  
  exports.addFile = function(file, position) {
    if (typeof position.content !== 'string') return;
    if (Object.prototype.hasOwnProperty.call(this.files, file)) return;
    this.files[file] = position.content;
  };
  
  /**
   * Adds a content source to the source map output if it has not already been added
   * @param {String} `source`
   * @param {Object} `position`
   */
  
  exports.addContent = function(source, position) {
    if (typeof position.content !== 'string') return;
    if (Object.prototype.hasOwnProperty.call(this.content, source)) return;
    this.map.setSourceContent(source, position.content);
  };
  
  /**
   * Applies any original source maps to the output and embeds the source file
   * contents in the source map.
   */
  
  exports.applySourceMaps = function() {
    Object.keys(this.files).forEach(function(file) {
      var content = this.files[file];
      this.map.setSourceContent(file, content);
  
      if (this.options.inputSourcemaps === true) {
        var originalMap = sourceMapResolve.resolveSync(content, file, fs.readFileSync);
        if (originalMap) {
          var map = new SourceMap.SourceMapConsumer(originalMap.map);
          var relativeTo = originalMap.sourcesRelativeTo;
          this.map.applySourceMap(map, file, unixify(path.dirname(relativeTo)));
        }
      }
    }, this);
  };
  
  /**
   * Process comments, drops sourceMap comments.
   * @param {Object} node
   */
  
  exports.comment = function(node) {
    if (/^# sourceMappingURL=/.test(node.comment)) {
      return this.emit('', node.position);
    }
    return this._comment(node);
  };
  
  /**
   * Convert backslash in the given string to forward slashes
   */
  
  function unixify(fp) {
    return fp.split(/\\+/).join('/');
  }
  