react / wstein / node_modules / browserify / node_modules / insert-module-globals / node_modules / combine-source-map / node_modules / source-map / lib / source-map / source-node.js
80559 views/* -*- Mode: js; js-indent-level: 2; -*- */1/*2* Copyright 2011 Mozilla Foundation and contributors3* Licensed under the New BSD license. See LICENSE or:4* http://opensource.org/licenses/BSD-3-Clause5*/6if (typeof define !== 'function') {7var define = require('amdefine')(module, require);8}9define(function (require, exports, module) {1011var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator;12var util = require('./util');1314// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other15// operating systems these days (capturing the result).16var REGEX_NEWLINE = /(\r?\n)/;1718// Newline character code for charCodeAt() comparisons19var NEWLINE_CODE = 10;2021// Private symbol for identifying `SourceNode`s when multiple versions of22// the source-map library are loaded. This MUST NOT CHANGE across23// versions!24var isSourceNode = "$$$isSourceNode$$$";2526/**27* SourceNodes provide a way to abstract over interpolating/concatenating28* snippets of generated JavaScript source code while maintaining the line and29* column information associated with the original source code.30*31* @param aLine The original line number.32* @param aColumn The original column number.33* @param aSource The original source's filename.34* @param aChunks Optional. An array of strings which are snippets of35* generated JS, or other SourceNodes.36* @param aName The original identifier.37*/38function SourceNode(aLine, aColumn, aSource, aChunks, aName) {39this.children = [];40this.sourceContents = {};41this.line = aLine == null ? null : aLine;42this.column = aColumn == null ? null : aColumn;43this.source = aSource == null ? null : aSource;44this.name = aName == null ? null : aName;45this[isSourceNode] = true;46if (aChunks != null) this.add(aChunks);47}4849/**50* Creates a SourceNode from generated code and a SourceMapConsumer.51*52* @param aGeneratedCode The generated code53* @param aSourceMapConsumer The SourceMap for the generated code54* @param aRelativePath Optional. The path that relative sources in the55* SourceMapConsumer should be relative to.56*/57SourceNode.fromStringWithSourceMap =58function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) {59// The SourceNode we want to fill with the generated code60// and the SourceMap61var node = new SourceNode();6263// All even indices of this array are one line of the generated code,64// while all odd indices are the newlines between two adjacent lines65// (since `REGEX_NEWLINE` captures its match).66// Processed fragments are removed from this array, by calling `shiftNextLine`.67var remainingLines = aGeneratedCode.split(REGEX_NEWLINE);68var shiftNextLine = function() {69var lineContents = remainingLines.shift();70// The last line of a file might not have a newline.71var newLine = remainingLines.shift() || "";72return lineContents + newLine;73};7475// We need to remember the position of "remainingLines"76var lastGeneratedLine = 1, lastGeneratedColumn = 0;7778// The generate SourceNodes we need a code range.79// To extract it current and last mapping is used.80// Here we store the last mapping.81var lastMapping = null;8283aSourceMapConsumer.eachMapping(function (mapping) {84if (lastMapping !== null) {85// We add the code from "lastMapping" to "mapping":86// First check if there is a new line in between.87if (lastGeneratedLine < mapping.generatedLine) {88var code = "";89// Associate first line with "lastMapping"90addMappingWithCode(lastMapping, shiftNextLine());91lastGeneratedLine++;92lastGeneratedColumn = 0;93// The remaining code is added without mapping94} else {95// There is no new line in between.96// Associate the code between "lastGeneratedColumn" and97// "mapping.generatedColumn" with "lastMapping"98var nextLine = remainingLines[0];99var code = nextLine.substr(0, mapping.generatedColumn -100lastGeneratedColumn);101remainingLines[0] = nextLine.substr(mapping.generatedColumn -102lastGeneratedColumn);103lastGeneratedColumn = mapping.generatedColumn;104addMappingWithCode(lastMapping, code);105// No more remaining code, continue106lastMapping = mapping;107return;108}109}110// We add the generated code until the first mapping111// to the SourceNode without any mapping.112// Each line is added as separate string.113while (lastGeneratedLine < mapping.generatedLine) {114node.add(shiftNextLine());115lastGeneratedLine++;116}117if (lastGeneratedColumn < mapping.generatedColumn) {118var nextLine = remainingLines[0];119node.add(nextLine.substr(0, mapping.generatedColumn));120remainingLines[0] = nextLine.substr(mapping.generatedColumn);121lastGeneratedColumn = mapping.generatedColumn;122}123lastMapping = mapping;124}, this);125// We have processed all mappings.126if (remainingLines.length > 0) {127if (lastMapping) {128// Associate the remaining code in the current line with "lastMapping"129addMappingWithCode(lastMapping, shiftNextLine());130}131// and add the remaining lines without any mapping132node.add(remainingLines.join(""));133}134135// Copy sourcesContent into SourceNode136aSourceMapConsumer.sources.forEach(function (sourceFile) {137var content = aSourceMapConsumer.sourceContentFor(sourceFile);138if (content != null) {139if (aRelativePath != null) {140sourceFile = util.join(aRelativePath, sourceFile);141}142node.setSourceContent(sourceFile, content);143}144});145146return node;147148function addMappingWithCode(mapping, code) {149if (mapping === null || mapping.source === undefined) {150node.add(code);151} else {152var source = aRelativePath153? util.join(aRelativePath, mapping.source)154: mapping.source;155node.add(new SourceNode(mapping.originalLine,156mapping.originalColumn,157source,158code,159mapping.name));160}161}162};163164/**165* Add a chunk of generated JS to this source node.166*167* @param aChunk A string snippet of generated JS code, another instance of168* SourceNode, or an array where each member is one of those things.169*/170SourceNode.prototype.add = function SourceNode_add(aChunk) {171if (Array.isArray(aChunk)) {172aChunk.forEach(function (chunk) {173this.add(chunk);174}, this);175}176else if (aChunk[isSourceNode] || typeof aChunk === "string") {177if (aChunk) {178this.children.push(aChunk);179}180}181else {182throw new TypeError(183"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk184);185}186return this;187};188189/**190* Add a chunk of generated JS to the beginning of this source node.191*192* @param aChunk A string snippet of generated JS code, another instance of193* SourceNode, or an array where each member is one of those things.194*/195SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {196if (Array.isArray(aChunk)) {197for (var i = aChunk.length-1; i >= 0; i--) {198this.prepend(aChunk[i]);199}200}201else if (aChunk[isSourceNode] || typeof aChunk === "string") {202this.children.unshift(aChunk);203}204else {205throw new TypeError(206"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk207);208}209return this;210};211212/**213* Walk over the tree of JS snippets in this node and its children. The214* walking function is called once for each snippet of JS and is passed that215* snippet and the its original associated source's line/column location.216*217* @param aFn The traversal function.218*/219SourceNode.prototype.walk = function SourceNode_walk(aFn) {220var chunk;221for (var i = 0, len = this.children.length; i < len; i++) {222chunk = this.children[i];223if (chunk[isSourceNode]) {224chunk.walk(aFn);225}226else {227if (chunk !== '') {228aFn(chunk, { source: this.source,229line: this.line,230column: this.column,231name: this.name });232}233}234}235};236237/**238* Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between239* each of `this.children`.240*241* @param aSep The separator.242*/243SourceNode.prototype.join = function SourceNode_join(aSep) {244var newChildren;245var i;246var len = this.children.length;247if (len > 0) {248newChildren = [];249for (i = 0; i < len-1; i++) {250newChildren.push(this.children[i]);251newChildren.push(aSep);252}253newChildren.push(this.children[i]);254this.children = newChildren;255}256return this;257};258259/**260* Call String.prototype.replace on the very right-most source snippet. Useful261* for trimming whitespace from the end of a source node, etc.262*263* @param aPattern The pattern to replace.264* @param aReplacement The thing to replace the pattern with.265*/266SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {267var lastChild = this.children[this.children.length - 1];268if (lastChild[isSourceNode]) {269lastChild.replaceRight(aPattern, aReplacement);270}271else if (typeof lastChild === 'string') {272this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);273}274else {275this.children.push(''.replace(aPattern, aReplacement));276}277return this;278};279280/**281* Set the source content for a source file. This will be added to the SourceMapGenerator282* in the sourcesContent field.283*284* @param aSourceFile The filename of the source file285* @param aSourceContent The content of the source file286*/287SourceNode.prototype.setSourceContent =288function SourceNode_setSourceContent(aSourceFile, aSourceContent) {289this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;290};291292/**293* Walk over the tree of SourceNodes. The walking function is called for each294* source file content and is passed the filename and source content.295*296* @param aFn The traversal function.297*/298SourceNode.prototype.walkSourceContents =299function SourceNode_walkSourceContents(aFn) {300for (var i = 0, len = this.children.length; i < len; i++) {301if (this.children[i][isSourceNode]) {302this.children[i].walkSourceContents(aFn);303}304}305306var sources = Object.keys(this.sourceContents);307for (var i = 0, len = sources.length; i < len; i++) {308aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);309}310};311312/**313* Return the string representation of this source node. Walks over the tree314* and concatenates all the various snippets together to one string.315*/316SourceNode.prototype.toString = function SourceNode_toString() {317var str = "";318this.walk(function (chunk) {319str += chunk;320});321return str;322};323324/**325* Returns the string representation of this source node along with a source326* map.327*/328SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {329var generated = {330code: "",331line: 1,332column: 0333};334var map = new SourceMapGenerator(aArgs);335var sourceMappingActive = false;336var lastOriginalSource = null;337var lastOriginalLine = null;338var lastOriginalColumn = null;339var lastOriginalName = null;340this.walk(function (chunk, original) {341generated.code += chunk;342if (original.source !== null343&& original.line !== null344&& original.column !== null) {345if(lastOriginalSource !== original.source346|| lastOriginalLine !== original.line347|| lastOriginalColumn !== original.column348|| lastOriginalName !== original.name) {349map.addMapping({350source: original.source,351original: {352line: original.line,353column: original.column354},355generated: {356line: generated.line,357column: generated.column358},359name: original.name360});361}362lastOriginalSource = original.source;363lastOriginalLine = original.line;364lastOriginalColumn = original.column;365lastOriginalName = original.name;366sourceMappingActive = true;367} else if (sourceMappingActive) {368map.addMapping({369generated: {370line: generated.line,371column: generated.column372}373});374lastOriginalSource = null;375sourceMappingActive = false;376}377for (var idx = 0, length = chunk.length; idx < length; idx++) {378if (chunk.charCodeAt(idx) === NEWLINE_CODE) {379generated.line++;380generated.column = 0;381// Mappings end at eol382if (idx + 1 === length) {383lastOriginalSource = null;384sourceMappingActive = false;385} else if (sourceMappingActive) {386map.addMapping({387source: original.source,388original: {389line: original.line,390column: original.column391},392generated: {393line: generated.line,394column: generated.column395},396name: original.name397});398}399} else {400generated.column++;401}402}403});404this.walkSourceContents(function (sourceFile, sourceContent) {405map.setSourceContent(sourceFile, sourceContent);406});407408return { code: generated.code, map: map };409};410411exports.SourceNode = SourceNode;412413});414415416