react / react-0.13.3 / examples / basic-commonjs / node_modules / browserify / node_modules / umd / node_modules / uglify-js / node_modules / source-map / lib / source-map / source-node.js
80766 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)/g;1718// Matches a Windows-style newline, or any character.19var REGEX_CHARACTER = /\r\n|[\s\S]/g;2021/**22* SourceNodes provide a way to abstract over interpolating/concatenating23* snippets of generated JavaScript source code while maintaining the line and24* column information associated with the original source code.25*26* @param aLine The original line number.27* @param aColumn The original column number.28* @param aSource The original source's filename.29* @param aChunks Optional. An array of strings which are snippets of30* generated JS, or other SourceNodes.31* @param aName The original identifier.32*/33function SourceNode(aLine, aColumn, aSource, aChunks, aName) {34this.children = [];35this.sourceContents = {};36this.line = aLine === undefined ? null : aLine;37this.column = aColumn === undefined ? null : aColumn;38this.source = aSource === undefined ? null : aSource;39this.name = aName === undefined ? null : aName;40if (aChunks != null) this.add(aChunks);41}4243/**44* Creates a SourceNode from generated code and a SourceMapConsumer.45*46* @param aGeneratedCode The generated code47* @param aSourceMapConsumer The SourceMap for the generated code48*/49SourceNode.fromStringWithSourceMap =50function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) {51// The SourceNode we want to fill with the generated code52// and the SourceMap53var node = new SourceNode();5455// All even indices of this array are one line of the generated code,56// while all odd indices are the newlines between two adjacent lines57// (since `REGEX_NEWLINE` captures its match).58// Processed fragments are removed from this array, by calling `shiftNextLine`.59var remainingLines = aGeneratedCode.split(REGEX_NEWLINE);60var shiftNextLine = function() {61var lineContents = remainingLines.shift();62// The last line of a file might not have a newline.63var newLine = remainingLines.shift() || "";64return lineContents + newLine;65};6667// We need to remember the position of "remainingLines"68var lastGeneratedLine = 1, lastGeneratedColumn = 0;6970// The generate SourceNodes we need a code range.71// To extract it current and last mapping is used.72// Here we store the last mapping.73var lastMapping = null;7475aSourceMapConsumer.eachMapping(function (mapping) {76if (lastMapping !== null) {77// We add the code from "lastMapping" to "mapping":78// First check if there is a new line in between.79if (lastGeneratedLine < mapping.generatedLine) {80var code = "";81// Associate first line with "lastMapping"82addMappingWithCode(lastMapping, shiftNextLine());83lastGeneratedLine++;84lastGeneratedColumn = 0;85// The remaining code is added without mapping86} else {87// There is no new line in between.88// Associate the code between "lastGeneratedColumn" and89// "mapping.generatedColumn" with "lastMapping"90var nextLine = remainingLines[0];91var code = nextLine.substr(0, mapping.generatedColumn -92lastGeneratedColumn);93remainingLines[0] = nextLine.substr(mapping.generatedColumn -94lastGeneratedColumn);95lastGeneratedColumn = mapping.generatedColumn;96addMappingWithCode(lastMapping, code);97// No more remaining code, continue98lastMapping = mapping;99return;100}101}102// We add the generated code until the first mapping103// to the SourceNode without any mapping.104// Each line is added as separate string.105while (lastGeneratedLine < mapping.generatedLine) {106node.add(shiftNextLine());107lastGeneratedLine++;108}109if (lastGeneratedColumn < mapping.generatedColumn) {110var nextLine = remainingLines[0];111node.add(nextLine.substr(0, mapping.generatedColumn));112remainingLines[0] = nextLine.substr(mapping.generatedColumn);113lastGeneratedColumn = mapping.generatedColumn;114}115lastMapping = mapping;116}, this);117// We have processed all mappings.118if (remainingLines.length > 0) {119if (lastMapping) {120// Associate the remaining code in the current line with "lastMapping"121addMappingWithCode(lastMapping, shiftNextLine());122}123// and add the remaining lines without any mapping124node.add(remainingLines.join(""));125}126127// Copy sourcesContent into SourceNode128aSourceMapConsumer.sources.forEach(function (sourceFile) {129var content = aSourceMapConsumer.sourceContentFor(sourceFile);130if (content) {131node.setSourceContent(sourceFile, content);132}133});134135return node;136137function addMappingWithCode(mapping, code) {138if (mapping === null || mapping.source === undefined) {139node.add(code);140} else {141node.add(new SourceNode(mapping.originalLine,142mapping.originalColumn,143mapping.source,144code,145mapping.name));146}147}148};149150/**151* Add a chunk of generated JS to this source node.152*153* @param aChunk A string snippet of generated JS code, another instance of154* SourceNode, or an array where each member is one of those things.155*/156SourceNode.prototype.add = function SourceNode_add(aChunk) {157if (Array.isArray(aChunk)) {158aChunk.forEach(function (chunk) {159this.add(chunk);160}, this);161}162else if (aChunk instanceof SourceNode || typeof aChunk === "string") {163if (aChunk) {164this.children.push(aChunk);165}166}167else {168throw new TypeError(169"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk170);171}172return this;173};174175/**176* Add a chunk of generated JS to the beginning of this source node.177*178* @param aChunk A string snippet of generated JS code, another instance of179* SourceNode, or an array where each member is one of those things.180*/181SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {182if (Array.isArray(aChunk)) {183for (var i = aChunk.length-1; i >= 0; i--) {184this.prepend(aChunk[i]);185}186}187else if (aChunk instanceof SourceNode || typeof aChunk === "string") {188this.children.unshift(aChunk);189}190else {191throw new TypeError(192"Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk193);194}195return this;196};197198/**199* Walk over the tree of JS snippets in this node and its children. The200* walking function is called once for each snippet of JS and is passed that201* snippet and the its original associated source's line/column location.202*203* @param aFn The traversal function.204*/205SourceNode.prototype.walk = function SourceNode_walk(aFn) {206var chunk;207for (var i = 0, len = this.children.length; i < len; i++) {208chunk = this.children[i];209if (chunk instanceof SourceNode) {210chunk.walk(aFn);211}212else {213if (chunk !== '') {214aFn(chunk, { source: this.source,215line: this.line,216column: this.column,217name: this.name });218}219}220}221};222223/**224* Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between225* each of `this.children`.226*227* @param aSep The separator.228*/229SourceNode.prototype.join = function SourceNode_join(aSep) {230var newChildren;231var i;232var len = this.children.length;233if (len > 0) {234newChildren = [];235for (i = 0; i < len-1; i++) {236newChildren.push(this.children[i]);237newChildren.push(aSep);238}239newChildren.push(this.children[i]);240this.children = newChildren;241}242return this;243};244245/**246* Call String.prototype.replace on the very right-most source snippet. Useful247* for trimming whitespace from the end of a source node, etc.248*249* @param aPattern The pattern to replace.250* @param aReplacement The thing to replace the pattern with.251*/252SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {253var lastChild = this.children[this.children.length - 1];254if (lastChild instanceof SourceNode) {255lastChild.replaceRight(aPattern, aReplacement);256}257else if (typeof lastChild === 'string') {258this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);259}260else {261this.children.push(''.replace(aPattern, aReplacement));262}263return this;264};265266/**267* Set the source content for a source file. This will be added to the SourceMapGenerator268* in the sourcesContent field.269*270* @param aSourceFile The filename of the source file271* @param aSourceContent The content of the source file272*/273SourceNode.prototype.setSourceContent =274function SourceNode_setSourceContent(aSourceFile, aSourceContent) {275this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;276};277278/**279* Walk over the tree of SourceNodes. The walking function is called for each280* source file content and is passed the filename and source content.281*282* @param aFn The traversal function.283*/284SourceNode.prototype.walkSourceContents =285function SourceNode_walkSourceContents(aFn) {286for (var i = 0, len = this.children.length; i < len; i++) {287if (this.children[i] instanceof SourceNode) {288this.children[i].walkSourceContents(aFn);289}290}291292var sources = Object.keys(this.sourceContents);293for (var i = 0, len = sources.length; i < len; i++) {294aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);295}296};297298/**299* Return the string representation of this source node. Walks over the tree300* and concatenates all the various snippets together to one string.301*/302SourceNode.prototype.toString = function SourceNode_toString() {303var str = "";304this.walk(function (chunk) {305str += chunk;306});307return str;308};309310/**311* Returns the string representation of this source node along with a source312* map.313*/314SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {315var generated = {316code: "",317line: 1,318column: 0319};320var map = new SourceMapGenerator(aArgs);321var sourceMappingActive = false;322var lastOriginalSource = null;323var lastOriginalLine = null;324var lastOriginalColumn = null;325var lastOriginalName = null;326this.walk(function (chunk, original) {327generated.code += chunk;328if (original.source !== null329&& original.line !== null330&& original.column !== null) {331if(lastOriginalSource !== original.source332|| lastOriginalLine !== original.line333|| lastOriginalColumn !== original.column334|| lastOriginalName !== original.name) {335map.addMapping({336source: original.source,337original: {338line: original.line,339column: original.column340},341generated: {342line: generated.line,343column: generated.column344},345name: original.name346});347}348lastOriginalSource = original.source;349lastOriginalLine = original.line;350lastOriginalColumn = original.column;351lastOriginalName = original.name;352sourceMappingActive = true;353} else if (sourceMappingActive) {354map.addMapping({355generated: {356line: generated.line,357column: generated.column358}359});360lastOriginalSource = null;361sourceMappingActive = false;362}363chunk.match(REGEX_CHARACTER).forEach(function (ch, idx, array) {364if (REGEX_NEWLINE.test(ch)) {365generated.line++;366generated.column = 0;367// Mappings end at eol368if (idx + 1 === array.length) {369lastOriginalSource = null;370sourceMappingActive = false;371} else if (sourceMappingActive) {372map.addMapping({373source: original.source,374original: {375line: original.line,376column: original.column377},378generated: {379line: generated.line,380column: generated.column381},382name: original.name383});384}385} else {386generated.column += ch.length;387}388});389});390this.walkSourceContents(function (sourceFile, sourceContent) {391map.setSourceContent(sourceFile, sourceContent);392});393394return { code: generated.code, map: map };395};396397exports.SourceNode = SourceNode;398399});400401402