| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 | 
							- /* -*- Mode: js; js-indent-level: 2; -*- */
 
- /*
 
-  * Copyright 2011 Mozilla Foundation and contributors
 
-  * Licensed under the New BSD license. See LICENSE or:
 
-  * http://opensource.org/licenses/BSD-3-Clause
 
-  */
 
- var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator;
 
- var util = require('./util');
 
- // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
 
- // operating systems these days (capturing the result).
 
- var REGEX_NEWLINE = /(\r?\n)/;
 
- // Newline character code for charCodeAt() comparisons
 
- var NEWLINE_CODE = 10;
 
- // Private symbol for identifying `SourceNode`s when multiple versions of
 
- // the source-map library are loaded. This MUST NOT CHANGE across
 
- // versions!
 
- var isSourceNode = "$$$isSourceNode$$$";
 
- /**
 
-  * SourceNodes provide a way to abstract over interpolating/concatenating
 
-  * snippets of generated JavaScript source code while maintaining the line and
 
-  * column information associated with the original source code.
 
-  *
 
-  * @param aLine The original line number.
 
-  * @param aColumn The original column number.
 
-  * @param aSource The original source's filename.
 
-  * @param aChunks Optional. An array of strings which are snippets of
 
-  *        generated JS, or other SourceNodes.
 
-  * @param aName The original identifier.
 
-  */
 
- function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
 
-   this.children = [];
 
-   this.sourceContents = {};
 
-   this.line = aLine == null ? null : aLine;
 
-   this.column = aColumn == null ? null : aColumn;
 
-   this.source = aSource == null ? null : aSource;
 
-   this.name = aName == null ? null : aName;
 
-   this[isSourceNode] = true;
 
-   if (aChunks != null) this.add(aChunks);
 
- }
 
- /**
 
-  * Creates a SourceNode from generated code and a SourceMapConsumer.
 
-  *
 
-  * @param aGeneratedCode The generated code
 
-  * @param aSourceMapConsumer The SourceMap for the generated code
 
-  * @param aRelativePath Optional. The path that relative sources in the
 
-  *        SourceMapConsumer should be relative to.
 
-  */
 
- SourceNode.fromStringWithSourceMap =
 
-   function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) {
 
-     // The SourceNode we want to fill with the generated code
 
-     // and the SourceMap
 
-     var node = new SourceNode();
 
-     // All even indices of this array are one line of the generated code,
 
-     // while all odd indices are the newlines between two adjacent lines
 
-     // (since `REGEX_NEWLINE` captures its match).
 
-     // Processed fragments are accessed by calling `shiftNextLine`.
 
-     var remainingLines = aGeneratedCode.split(REGEX_NEWLINE);
 
-     var remainingLinesIndex = 0;
 
-     var shiftNextLine = function() {
 
-       var lineContents = getNextLine();
 
-       // The last line of a file might not have a newline.
 
-       var newLine = getNextLine() || "";
 
-       return lineContents + newLine;
 
-       function getNextLine() {
 
-         return remainingLinesIndex < remainingLines.length ?
 
-             remainingLines[remainingLinesIndex++] : undefined;
 
-       }
 
-     };
 
-     // We need to remember the position of "remainingLines"
 
-     var lastGeneratedLine = 1, lastGeneratedColumn = 0;
 
-     // The generate SourceNodes we need a code range.
 
-     // To extract it current and last mapping is used.
 
-     // Here we store the last mapping.
 
-     var lastMapping = null;
 
-     aSourceMapConsumer.eachMapping(function (mapping) {
 
-       if (lastMapping !== null) {
 
-         // We add the code from "lastMapping" to "mapping":
 
-         // First check if there is a new line in between.
 
-         if (lastGeneratedLine < mapping.generatedLine) {
 
-           // Associate first line with "lastMapping"
 
-           addMappingWithCode(lastMapping, shiftNextLine());
 
-           lastGeneratedLine++;
 
-           lastGeneratedColumn = 0;
 
-           // The remaining code is added without mapping
 
-         } else {
 
-           // There is no new line in between.
 
-           // Associate the code between "lastGeneratedColumn" and
 
-           // "mapping.generatedColumn" with "lastMapping"
 
-           var nextLine = remainingLines[remainingLinesIndex] || '';
 
-           var code = nextLine.substr(0, mapping.generatedColumn -
 
-                                         lastGeneratedColumn);
 
-           remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn -
 
-                                               lastGeneratedColumn);
 
-           lastGeneratedColumn = mapping.generatedColumn;
 
-           addMappingWithCode(lastMapping, code);
 
-           // No more remaining code, continue
 
-           lastMapping = mapping;
 
-           return;
 
-         }
 
-       }
 
-       // We add the generated code until the first mapping
 
-       // to the SourceNode without any mapping.
 
-       // Each line is added as separate string.
 
-       while (lastGeneratedLine < mapping.generatedLine) {
 
-         node.add(shiftNextLine());
 
-         lastGeneratedLine++;
 
-       }
 
-       if (lastGeneratedColumn < mapping.generatedColumn) {
 
-         var nextLine = remainingLines[remainingLinesIndex] || '';
 
-         node.add(nextLine.substr(0, mapping.generatedColumn));
 
-         remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn);
 
-         lastGeneratedColumn = mapping.generatedColumn;
 
-       }
 
-       lastMapping = mapping;
 
-     }, this);
 
-     // We have processed all mappings.
 
-     if (remainingLinesIndex < remainingLines.length) {
 
-       if (lastMapping) {
 
-         // Associate the remaining code in the current line with "lastMapping"
 
-         addMappingWithCode(lastMapping, shiftNextLine());
 
-       }
 
-       // and add the remaining lines without any mapping
 
-       node.add(remainingLines.splice(remainingLinesIndex).join(""));
 
-     }
 
-     // Copy sourcesContent into SourceNode
 
-     aSourceMapConsumer.sources.forEach(function (sourceFile) {
 
-       var content = aSourceMapConsumer.sourceContentFor(sourceFile);
 
-       if (content != null) {
 
-         if (aRelativePath != null) {
 
-           sourceFile = util.join(aRelativePath, sourceFile);
 
-         }
 
-         node.setSourceContent(sourceFile, content);
 
-       }
 
-     });
 
-     return node;
 
-     function addMappingWithCode(mapping, code) {
 
-       if (mapping === null || mapping.source === undefined) {
 
-         node.add(code);
 
-       } else {
 
-         var source = aRelativePath
 
-           ? util.join(aRelativePath, mapping.source)
 
-           : mapping.source;
 
-         node.add(new SourceNode(mapping.originalLine,
 
-                                 mapping.originalColumn,
 
-                                 source,
 
-                                 code,
 
-                                 mapping.name));
 
-       }
 
-     }
 
-   };
 
- /**
 
-  * Add a chunk of generated JS to this source node.
 
-  *
 
-  * @param aChunk A string snippet of generated JS code, another instance of
 
-  *        SourceNode, or an array where each member is one of those things.
 
-  */
 
- SourceNode.prototype.add = function SourceNode_add(aChunk) {
 
-   if (Array.isArray(aChunk)) {
 
-     aChunk.forEach(function (chunk) {
 
-       this.add(chunk);
 
-     }, this);
 
-   }
 
-   else if (aChunk[isSourceNode] || typeof aChunk === "string") {
 
-     if (aChunk) {
 
-       this.children.push(aChunk);
 
-     }
 
-   }
 
-   else {
 
-     throw new TypeError(
 
-       "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
 
-     );
 
-   }
 
-   return this;
 
- };
 
- /**
 
-  * Add a chunk of generated JS to the beginning of this source node.
 
-  *
 
-  * @param aChunk A string snippet of generated JS code, another instance of
 
-  *        SourceNode, or an array where each member is one of those things.
 
-  */
 
- SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {
 
-   if (Array.isArray(aChunk)) {
 
-     for (var i = aChunk.length-1; i >= 0; i--) {
 
-       this.prepend(aChunk[i]);
 
-     }
 
-   }
 
-   else if (aChunk[isSourceNode] || typeof aChunk === "string") {
 
-     this.children.unshift(aChunk);
 
-   }
 
-   else {
 
-     throw new TypeError(
 
-       "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
 
-     );
 
-   }
 
-   return this;
 
- };
 
- /**
 
-  * Walk over the tree of JS snippets in this node and its children. The
 
-  * walking function is called once for each snippet of JS and is passed that
 
-  * snippet and the its original associated source's line/column location.
 
-  *
 
-  * @param aFn The traversal function.
 
-  */
 
- SourceNode.prototype.walk = function SourceNode_walk(aFn) {
 
-   var chunk;
 
-   for (var i = 0, len = this.children.length; i < len; i++) {
 
-     chunk = this.children[i];
 
-     if (chunk[isSourceNode]) {
 
-       chunk.walk(aFn);
 
-     }
 
-     else {
 
-       if (chunk !== '') {
 
-         aFn(chunk, { source: this.source,
 
-                      line: this.line,
 
-                      column: this.column,
 
-                      name: this.name });
 
-       }
 
-     }
 
-   }
 
- };
 
- /**
 
-  * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between
 
-  * each of `this.children`.
 
-  *
 
-  * @param aSep The separator.
 
-  */
 
- SourceNode.prototype.join = function SourceNode_join(aSep) {
 
-   var newChildren;
 
-   var i;
 
-   var len = this.children.length;
 
-   if (len > 0) {
 
-     newChildren = [];
 
-     for (i = 0; i < len-1; i++) {
 
-       newChildren.push(this.children[i]);
 
-       newChildren.push(aSep);
 
-     }
 
-     newChildren.push(this.children[i]);
 
-     this.children = newChildren;
 
-   }
 
-   return this;
 
- };
 
- /**
 
-  * Call String.prototype.replace on the very right-most source snippet. Useful
 
-  * for trimming whitespace from the end of a source node, etc.
 
-  *
 
-  * @param aPattern The pattern to replace.
 
-  * @param aReplacement The thing to replace the pattern with.
 
-  */
 
- SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {
 
-   var lastChild = this.children[this.children.length - 1];
 
-   if (lastChild[isSourceNode]) {
 
-     lastChild.replaceRight(aPattern, aReplacement);
 
-   }
 
-   else if (typeof lastChild === 'string') {
 
-     this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);
 
-   }
 
-   else {
 
-     this.children.push(''.replace(aPattern, aReplacement));
 
-   }
 
-   return this;
 
- };
 
- /**
 
-  * Set the source content for a source file. This will be added to the SourceMapGenerator
 
-  * in the sourcesContent field.
 
-  *
 
-  * @param aSourceFile The filename of the source file
 
-  * @param aSourceContent The content of the source file
 
-  */
 
- SourceNode.prototype.setSourceContent =
 
-   function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
 
-     this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
 
-   };
 
- /**
 
-  * Walk over the tree of SourceNodes. The walking function is called for each
 
-  * source file content and is passed the filename and source content.
 
-  *
 
-  * @param aFn The traversal function.
 
-  */
 
- SourceNode.prototype.walkSourceContents =
 
-   function SourceNode_walkSourceContents(aFn) {
 
-     for (var i = 0, len = this.children.length; i < len; i++) {
 
-       if (this.children[i][isSourceNode]) {
 
-         this.children[i].walkSourceContents(aFn);
 
-       }
 
-     }
 
-     var sources = Object.keys(this.sourceContents);
 
-     for (var i = 0, len = sources.length; i < len; i++) {
 
-       aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);
 
-     }
 
-   };
 
- /**
 
-  * Return the string representation of this source node. Walks over the tree
 
-  * and concatenates all the various snippets together to one string.
 
-  */
 
- SourceNode.prototype.toString = function SourceNode_toString() {
 
-   var str = "";
 
-   this.walk(function (chunk) {
 
-     str += chunk;
 
-   });
 
-   return str;
 
- };
 
- /**
 
-  * Returns the string representation of this source node along with a source
 
-  * map.
 
-  */
 
- SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {
 
-   var generated = {
 
-     code: "",
 
-     line: 1,
 
-     column: 0
 
-   };
 
-   var map = new SourceMapGenerator(aArgs);
 
-   var sourceMappingActive = false;
 
-   var lastOriginalSource = null;
 
-   var lastOriginalLine = null;
 
-   var lastOriginalColumn = null;
 
-   var lastOriginalName = null;
 
-   this.walk(function (chunk, original) {
 
-     generated.code += chunk;
 
-     if (original.source !== null
 
-         && original.line !== null
 
-         && original.column !== null) {
 
-       if(lastOriginalSource !== original.source
 
-          || lastOriginalLine !== original.line
 
-          || lastOriginalColumn !== original.column
 
-          || lastOriginalName !== original.name) {
 
-         map.addMapping({
 
-           source: original.source,
 
-           original: {
 
-             line: original.line,
 
-             column: original.column
 
-           },
 
-           generated: {
 
-             line: generated.line,
 
-             column: generated.column
 
-           },
 
-           name: original.name
 
-         });
 
-       }
 
-       lastOriginalSource = original.source;
 
-       lastOriginalLine = original.line;
 
-       lastOriginalColumn = original.column;
 
-       lastOriginalName = original.name;
 
-       sourceMappingActive = true;
 
-     } else if (sourceMappingActive) {
 
-       map.addMapping({
 
-         generated: {
 
-           line: generated.line,
 
-           column: generated.column
 
-         }
 
-       });
 
-       lastOriginalSource = null;
 
-       sourceMappingActive = false;
 
-     }
 
-     for (var idx = 0, length = chunk.length; idx < length; idx++) {
 
-       if (chunk.charCodeAt(idx) === NEWLINE_CODE) {
 
-         generated.line++;
 
-         generated.column = 0;
 
-         // Mappings end at eol
 
-         if (idx + 1 === length) {
 
-           lastOriginalSource = null;
 
-           sourceMappingActive = false;
 
-         } else if (sourceMappingActive) {
 
-           map.addMapping({
 
-             source: original.source,
 
-             original: {
 
-               line: original.line,
 
-               column: original.column
 
-             },
 
-             generated: {
 
-               line: generated.line,
 
-               column: generated.column
 
-             },
 
-             name: original.name
 
-           });
 
-         }
 
-       } else {
 
-         generated.column++;
 
-       }
 
-     }
 
-   });
 
-   this.walkSourceContents(function (sourceFile, sourceContent) {
 
-     map.setSourceContent(sourceFile, sourceContent);
 
-   });
 
-   return { code: generated.code, map: map };
 
- };
 
- exports.SourceNode = SourceNode;
 
 
  |