lib/source-replacer.js
function sourceReplacer(source, replacements) {

  // shared
  var getBefore = getField('before');
  var getAfter  = getField('after');

  // split source code into lines, include the delimiter
  var lines = source.split(/(\r?\n)/g);

  // split each line further by the replacements
  for (var i = 0; i < lines.length; i += 2) {
    var split = lines[i] = [].concat(lines[i]); // initialise each line text into an array
    for (var before in replacements) {
      var after = replacements[before];
      split.forEach(splitByReplacement(before, after));
    }
  }

  // utility methods
  return {
    toStringBefore: toStringBefore,
    toStringAfter : toStringAfter,
    getColumnAfter: getColumnAfter
  };

  /**
   * String representation of text before replacement
   * @returns {string}
   */
  function toStringBefore() {
    return lines.map(getBefore).join('');
  }

  /**
   * String representation of text after replacement
   * @returns {string}
   */
  function toStringAfter() {
    return lines.map(getAfter).join('');
  }

  /**
   * Get a column position delta as at the given line and column that has occured as a result of replacement.
   * @param {number} lineIndex The line in the original source at which to evaluate the offset
   * @param {number} columnIndex The column in the original source at which to evaluate the offset
   * @returns {number} A column offset in characters
   */
  function getColumnAfter(lineIndex, columnIndex) {
    if (lineIndex in lines) {
      var line   = lines[lineIndex];
      var count  = 0;
      var offset = 0;
      for (var i = 0; i < line.length; i++) {
        var widthBefore = getBefore(line[i]).length;
        var widthAfter  = getAfter(line[i]).length;
        var nextCount   = count + widthBefore;
        if (nextCount > columnIndex) {
          break;
        } else {
          count   = nextCount;
          offset += widthAfter - widthBefore;
        }
      }
      return columnIndex + offset;
    } else {
      throw new Error('Line index is out of range');
    }
  }
}
function sourceReplacer(source, replacements) {

  // shared
  var getBefore = getField('before');
  var getAfter  = getField('after');

  // split source code into lines, include the delimiter
  var lines = source.split(/(\r?\n)/g);

  // split each line further by the replacements
  for (var i = 0; i < lines.length; i += 2) {
    var split = lines[i] = [].concat(lines[i]); // initialise each line text into an array
    for (var before in replacements) {
      var after = replacements[before];
      split.forEach(splitByReplacement(before, after));
    }
  }

  // utility methods
  return {
    toStringBefore: toStringBefore,
    toStringAfter : toStringAfter,
    getColumnAfter: getColumnAfter
  };

  /**
   * String representation of text before replacement
   * @returns {string}
   */
  function toStringBefore() {
    return lines.map(getBefore).join('');
  }

  /**
   * String representation of text after replacement
   * @returns {string}
   */
  function toStringAfter() {
    return lines.map(getAfter).join('');
  }

  /**
   * Get a column position delta as at the given line and column that has occured as a result of replacement.
   * @param {number} lineIndex The line in the original source at which to evaluate the offset
   * @param {number} columnIndex The column in the original source at which to evaluate the offset
   * @returns {number} A column offset in characters
   */
  function getColumnAfter(lineIndex, columnIndex) {
    if (lineIndex in lines) {
      var line   = lines[lineIndex];
      var count  = 0;
      var offset = 0;
      for (var i = 0; i < line.length; i++) {
        var widthBefore = getBefore(line[i]).length;
        var widthAfter  = getAfter(line[i]).length;
        var nextCount   = count + widthBefore;
        if (nextCount > columnIndex) {
          break;
        } else {
          count   = nextCount;
          offset += widthAfter - widthBefore;
        }
      }
      return columnIndex + offset;
    } else {
      throw new Error('Line index is out of range');
    }
  }
}
function sourceReplacer ( source , replacements ) { // shared var getBefore = getField ( 'before' ) ; var getAfter = getField ( 'after' ) ; // split source code into lines, include the delimiter var lines = source . split ( / (\r?\n) / g ) ; // split each line further by the replacements for ( var i = 0 ; i < lines . length ; i += 2 ) { var split = lines [ i ] = [ ] . concat ( lines [ i ] ) ; // initialise each line text into an array for ( var before in replacements ) { var after = replacements [ before ] ; split . forEach ( splitByReplacement ( before , after ) ) ; } } // utility methods return { toStringBefore : toStringBefore , toStringAfter : toStringAfter , getColumnAfter : getColumnAfter } ; /**
   * String representation of text before replacement
   * @returns {string}
   */ function toStringBefore ( ) { return lines . map ( getBefore ) . join ( '' ) ; } /**
   * String representation of text after replacement
   * @returns {string}
   */ function toStringAfter ( ) { return lines . map ( getAfter ) . join ( '' ) ; } /**
   * Get a column position delta as at the given line and column that has occured as a result of replacement.
   * @param {number} lineIndex The line in the original source at which to evaluate the offset
   * @param {number} columnIndex The column in the original source at which to evaluate the offset
   * @returns {number} A column offset in characters
   */ function getColumnAfter ( lineIndex , columnIndex ) { if ( lineIndex in lines ) { var line = lines [ lineIndex ] ; var count = 0 ; var offset = 0 ; for ( var i = 0 ; i < line . length ; i ++ ) { var widthBefore = getBefore ( line [ i ] ) . length ; var widthAfter = getAfter ( line [ i ] ) . length ; var nextCount = count + widthBefore ; if ( nextCount > columnIndex ) { break ; } else { count = nextCount ; offset += widthAfter - widthBefore ; } } return columnIndex + offset ; } else { throw new Error ( 'Line index is out of range' ) ; } } }
Make replacements to the given source code and return a set of methods to utilise it.
@param {string} source Source code text without source-map comment
@param {object} replacements A hash of replacements to make
@returns {{toStringBefore:function, toStringAfter:function, getColumnAfter:function}} A set of methods
Make replacements to the given source code and return a set of methods to utilise it .