UNPKG

jsx

Version:

a faster, safer, easier JavaScript

1,125 lines (1,009 loc) 37.5 kB
/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1(the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is GCLI. * * The Initial Developer of the Original Code is * The Mozilla Foundation * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Joe Walker <jwalker@mozilla.com> (Original Author) * Nick Fitzgerald <nfitzgerald@mozilla.com> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /** * Define a module along with a payload. * @param {string} moduleName Name for the payload * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec * @param {function} payload Function with (require, exports, module) params */ function define(moduleName, deps, payload) { if (typeof moduleName != "string") { throw new TypeError('Expected string, got: ' + moduleName); } if (arguments.length == 2) { payload = deps; } if (moduleName in define.modules) { throw new Error("Module already defined: " + moduleName); } define.modules[moduleName] = payload; }; /** * The global store of un-instantiated modules */ define.modules = {}; /** * We invoke require() in the context of a Domain so we can have multiple * sets of modules running separate from each other. * This contrasts with JSMs which are singletons, Domains allows us to * optionally load a CommonJS module twice with separate data each time. * Perhaps you want 2 command lines with a different set of commands in each, * for example. */ function Domain() { this.modules = {}; this._currentModule = null; } (function () { /** * Lookup module names and resolve them by calling the definition function if * needed. * There are 2 ways to call this, either with an array of dependencies and a * callback to call when the dependencies are found (which can happen * asynchronously in an in-page context) or with a single string an no callback * where the dependency is resolved synchronously and returned. * The API is designed to be compatible with the CommonJS AMD spec and * RequireJS. * @param {string[]|string} deps A name, or names for the payload * @param {function|undefined} callback Function to call when the dependencies * are resolved * @return {undefined|object} The module required or undefined for * array/callback method */ Domain.prototype.require = function(deps, callback) { if (Array.isArray(deps)) { var params = deps.map(function(dep) { return this.lookup(dep); }, this); if (callback) { callback.apply(null, params); } return undefined; } else { return this.lookup(deps); } }; function normalize(path) { var bits = path.split('/'); var i = 1; while (i < bits.length) { if (bits[i] === '..') { bits.splice(i-1, 1); } else if (bits[i] === '.') { bits.splice(i, 1); } else { i++; } } return bits.join('/'); } function join(a, b) { a = a.trim(); b = b.trim(); if (/^\//.test(b)) { return b; } else { return a.replace(/\/*$/, '/') + b; } } function dirname(path) { var bits = path.split('/'); bits.pop(); return bits.join('/'); } /** * Lookup module names and resolve them by calling the definition function if * needed. * @param {string} moduleName A name for the payload to lookup * @return {object} The module specified by aModuleName or null if not found. */ Domain.prototype.lookup = function(moduleName) { if (/^\./.test(moduleName)) { moduleName = normalize(join(dirname(this._currentModule), moduleName)); } if (moduleName in this.modules) { var module = this.modules[moduleName]; return module; } if (!(moduleName in define.modules)) { throw new Error("Module not defined: " + moduleName); } var module = define.modules[moduleName]; if (typeof module == "function") { var exports = {}; var previousModule = this._currentModule; this._currentModule = moduleName; module(this.require.bind(this), exports, { id: moduleName, uri: "" }); this._currentModule = previousModule; module = exports; } // cache the resulting module object for next time this.modules[moduleName] = module; return module; }; }()); define.Domain = Domain; define.globalDomain = new Domain(); var require = define.globalDomain.require.bind(define.globalDomain); /* -*- 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 */ define('lib/source-map/source-map-generator', ['require', 'exports', 'module' , 'lib/source-map/base64-vlq', 'lib/source-map/util', 'lib/source-map/array-set'], function(require, exports, module) { var base64VLQ = require('./base64-vlq'); var util = require('./util'); var ArraySet = require('./array-set').ArraySet; /** * An instance of the SourceMapGenerator represents a source map which is * being built incrementally. To create a new one, you must pass an object * with the following properties: * * - file: The filename of the generated source. * - sourceRoot: An optional root for all URLs in this source map. */ function SourceMapGenerator(aArgs) { this._file = util.getArg(aArgs, 'file'); this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); this._sources = new ArraySet(); this._names = new ArraySet(); this._mappings = []; } SourceMapGenerator.prototype._version = 3; /** * Add a single mapping from original source line and column to the generated * source's line and column for this source map being created. The mapping * object should have the following properties: * * - generated: An object with the generated line and column positions. * - original: An object with the original line and column positions. * - source: The original source file (relative to the sourceRoot). * - name: An optional original token name for this mapping. */ SourceMapGenerator.prototype.addMapping = function SourceMapGenerator_addMapping(aArgs) { var generated = util.getArg(aArgs, 'generated'); var original = util.getArg(aArgs, 'original', null); var source = util.getArg(aArgs, 'source', null); var name = util.getArg(aArgs, 'name', null); this._validateMapping(generated, original, source, name); if (source && !this._sources.has(source)) { this._sources.add(source); } if (name && !this._names.has(name)) { this._names.add(name); } this._mappings.push({ generated: generated, original: original, source: source, name: name }); }; /** * A mapping can have one of the three levels of data: * * 1. Just the generated position. * 2. The Generated position, original position, and original source. * 3. Generated and original position, original source, as well as a name * token. * * To maintain consistency, we validate that any new mapping being added falls * in to one of these categories. */ SourceMapGenerator.prototype._validateMapping = function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, aName) { if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) { // Case 1. return; } else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aOriginal && 'line' in aOriginal && 'column' in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) { // Cases 2 and 3. return; } else { throw new Error('Invalid mapping.'); } }; /** * Serialize the accumulated mappings in to the stream of base 64 VLQs * specified by the source map format. */ SourceMapGenerator.prototype._serializeMappings = function SourceMapGenerator_serializeMappings() { var previousGeneratedColumn = 0; var previousGeneratedLine = 1; var previousOriginalColumn = 0; var previousOriginalLine = 0; var previousName = 0; var previousSource = 0; var result = ''; var mapping; // The mappings must be guarenteed to be in sorted order before we start // serializing them or else the generated line numbers (which are defined // via the ';' separators) will be all messed up. Note: it might be more // performant to maintain the sorting as we insert them, rather than as we // serialize them, but the big O is the same either way. this._mappings.sort(function (mappingA, mappingB) { var cmp = mappingA.generated.line - mappingB.generated.line; return cmp === 0 ? mappingA.generated.column - mappingB.generated.column : cmp; }); for (var i = 0, len = this._mappings.length; i < len; i++) { mapping = this._mappings[i]; if (mapping.generated.line !== previousGeneratedLine) { previousGeneratedColumn = 0; while (mapping.generated.line !== previousGeneratedLine) { result += ';'; previousGeneratedLine++; } } else { if (i > 0) { result += ','; } } result += base64VLQ.encode(mapping.generated.column - previousGeneratedColumn); previousGeneratedColumn = mapping.generated.column; if (mapping.source && mapping.original) { result += base64VLQ.encode(this._sources.indexOf(mapping.source) - previousSource); previousSource = this._sources.indexOf(mapping.source); // lines are stored 0-based in SourceMap spec version 3 result += base64VLQ.encode(mapping.original.line - 1 - previousOriginalLine); previousOriginalLine = mapping.original.line - 1; result += base64VLQ.encode(mapping.original.column - previousOriginalColumn); previousOriginalColumn = mapping.original.column; if (mapping.name) { result += base64VLQ.encode(this._names.indexOf(mapping.name) - previousName); previousName = this._names.indexOf(mapping.name); } } } return result; }; /** * Render the source map being generated to a string. */ SourceMapGenerator.prototype.toString = function SourceMapGenerator_toString() { var map = { version: this._version, file: this._file, sources: this._sources.toArray(), names: this._names.toArray(), mappings: this._serializeMappings() }; if (this._sourceRoot) { map.sourceRoot = this._sourceRoot; } return JSON.stringify(map); }; exports.SourceMapGenerator = SourceMapGenerator; }); /* -*- 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 */ define('lib/source-map/base64-vlq', ['require', 'exports', 'module' , 'lib/source-map/base64'], function(require, exports, module) { var base64 = require('./base64'); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, // the next four bits are the actual value, and the 6th bit is the // continuation bit. The continuation bit tells us whether there are more // digits in this value following this digit. // // Continuation // | Sign // | | // V V // 101011 var VLQ_BASE_SHIFT = 5; // binary: 100000 var VLQ_BASE = 1 << VLQ_BASE_SHIFT; // binary: 011111 var VLQ_BASE_MASK = VLQ_BASE - 1; // binary: 100000 var VLQ_CONTINUATION_BIT = VLQ_BASE; /** * Converts from a two-complement value to a value where the sign bit is * is placed in the least significant bit. For example, as decimals: * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) */ function toVLQSigned(aValue) { return aValue < 0 ? ((-aValue) << 1) + 1 : (aValue << 1) + 0; } /** * Converts to a two-complement value from a value where the sign bit is * is placed in the least significant bit. For example, as decimals: * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 */ function fromVLQSigned(aValue) { var isNegative = (aValue & 1) === 1; var shifted = aValue >> 1; return isNegative ? -shifted : shifted; } /** * Returns the base 64 VLQ encoded value. */ exports.encode = function base64VLQ_encode(aValue) { var encoded = ""; var digit; var vlq = toVLQSigned(aValue); do { digit = vlq & VLQ_BASE_MASK; vlq >>>= VLQ_BASE_SHIFT; if (vlq > 0) { // There are still more digits in this value, so we must make sure the // continuation bit is marked. digit |= VLQ_CONTINUATION_BIT; } encoded += base64.encode(digit); } while (vlq > 0); return encoded; }; /** * Decodes the next base 64 VLQ value from the given string and returns the * value and the rest of the string. */ exports.decode = function base64VLQ_decode(aStr) { var i = 0; var strLen = aStr.length; var result = 0; var shift = 0; var continuation, digit; do { if (i >= strLen) { throw new Error("Expected more digits in base 64 VLQ value."); } digit = base64.decode(aStr.charAt(i++)); continuation = !!(digit & VLQ_CONTINUATION_BIT); digit &= VLQ_BASE_MASK; result = result + (digit << shift); shift += VLQ_BASE_SHIFT; } while (continuation); return { value: fromVLQSigned(result), rest: aStr.slice(i) }; }; }); /* -*- 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 */ define('lib/source-map/base64', ['require', 'exports', 'module' ], function(require, exports, module) { var charToIntMap = {}; var intToCharMap = {}; 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' .split('') .forEach(function (ch, index) { charToIntMap[ch] = index; intToCharMap[index] = ch; }); /** * Encode an integer in the range of 0 to 63 to a single base 64 digit. */ exports.encode = function base64_encode(aNumber) { if (aNumber in intToCharMap) { return intToCharMap[aNumber]; } throw new TypeError("Must be between 0 and 63: " + aNumber); }; /** * Decode a single base 64 digit to an integer. */ exports.decode = function base64_decode(aChar) { if (aChar in charToIntMap) { return charToIntMap[aChar]; } throw new TypeError("Not a valid base 64 digit: " + aChar); }; }); /* -*- 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 */ define('lib/source-map/util', ['require', 'exports', 'module' ], function(require, exports, module) { /** * This is a helper function for getting values from parameter/options * objects. * * @param args The object we are extracting values from * @param name The name of the property we are getting. * @param defaultValue An optional value to return if the property is missing * from the object. If this is not specified and the property is missing, an * error will be thrown. */ function getArg(aArgs, aName, aDefaultValue) { if (aName in aArgs) { return aArgs[aName]; } else if (arguments.length === 3) { return aDefaultValue; } else { throw new Error('"' + aName + '" is a required argument.'); } } exports.getArg = getArg; function join(aRoot, aPath) { return aPath.charAt(0) === '/' ? aPath : aRoot.replace(/\/*$/, '') + '/' + aPath; } exports.join = join; }); /* -*- 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 */ define('lib/source-map/array-set', ['require', 'exports', 'module' ], function(require, exports, module) { /** * A data structure which is a combination of an array and a set. Adding a new * member is O(1), testing for membership is O(1), and finding the index of an * element is O(1). Removing elements from the set is not supported. Only * strings are supported for membership. */ function ArraySet() { this._array = []; this._set = {}; } /** * Static method for creating ArraySet instances from an existing array. */ ArraySet.fromArray = function ArraySet_fromArray(aArray) { var set = new ArraySet(); for (var i = 0, len = aArray.length; i < len; i++) { set.add(aArray[i]); } return set; }; /** * Add the given string to this set. * * @param String str */ ArraySet.prototype.add = function ArraySet_add(aStr) { if (this.has(aStr)) { // Already a member; nothing to do. return; } var idx = this._array.length; this._array.push(aStr); this._set[aStr] = idx; }; /** * Is the given string a member of this set? * * @param String str */ ArraySet.prototype.has = function ArraySet_has(aStr) { return Object.prototype.hasOwnProperty.call(this._set, aStr); }; /** * What is the index of the given string in the array? * * @param String str */ ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { if (this.has(aStr)) { return this._set[aStr]; } throw new Error('"' + aStr + '" is not in the set.'); }; /** * What is the element at the given index? * * @param Number idx */ ArraySet.prototype.at = function ArraySet_at(aIdx) { if (aIdx >= 0 && aIdx < this._array.length) { return this._array[aIdx]; } throw new Error('No element indexed by ' + aIdx); }; /** * Returns the array representation of this set (which has the proper indices * indicated by indexOf). Note that this is a copy of the internal array used * for storing the members so that no one can mess with internal state. */ ArraySet.prototype.toArray = function ArraySet_toArray() { return this._array.slice(); }; exports.ArraySet = ArraySet; }); /* -*- 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 */ define('lib/source-map/source-map-consumer', ['require', 'exports', 'module' , 'lib/source-map/util', 'lib/source-map/binary-search', 'lib/source-map/array-set', 'lib/source-map/base64-vlq'], function(require, exports, module) { var util = require('./util'); var binarySearch = require('./binary-search'); var ArraySet = require('./array-set').ArraySet; var base64VLQ = require('./base64-vlq'); // TODO: bug 673487 // // Sometime in the future, if we decide we need to be able to query where in // the generated source a peice of the original code came from, we may want to // add a slot `_originalMappings` which would be an object keyed by the // original source and whose value would be an array of mappings ordered by // original line/col rather than generated (which is what we have now in // `_generatedMappings`). /** * A SourceMapConsumer instance represents a parsed source map which we can * query for information about the original file positions by giving it a file * position in the generated source. * * The only parameter is the raw source map (either as a JSON string, or * already parsed to an object). According to the spec, source maps have the * following attributes: * * - version: Which version of the source map spec this map is following. * - sources: An array of URLs to the original source files. * - names: An array of identifiers which can be referrenced by individual mappings. * - sourceRoot: Optional. The URL root from which all sources are relative. * - mappings: A string of base64 VLQs which contain the actual mappings. * - file: The generated file this source map is associated with. */ function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; if (typeof aSourceMap === 'string') { sourceMap = JSON.parse(aSourceMap); } var version = util.getArg(sourceMap, 'version'); var sources = util.getArg(sourceMap, 'sources'); var names = util.getArg(sourceMap, 'names'); var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); var mappings = util.getArg(sourceMap, 'mappings'); var file = util.getArg(sourceMap, 'file'); if (version !== this._version) { throw new Error('Unsupported version: ' + version); } this._names = ArraySet.fromArray(names); this._sources = ArraySet.fromArray(sources); this._generatedMappings = []; this._parseMappings(mappings, sourceRoot); } /** * The version of the source mapping spec that we are consuming. */ SourceMapConsumer.prototype._version = 3; /** * Parse the mappings in a string in to a data structure which we can easily * query (an ordered list in this._generatedMappings). */ SourceMapConsumer.prototype._parseMappings = function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { var generatedLine = 1; var previousGeneratedColumn = 0; var previousOriginalLine = 0; var previousOriginalColumn = 0; var previousSource = 0; var previousName = 0; var mappingSeparator = /^[,;]/; var str = aStr; var mapping; var temp; while (str.length > 0) { if (str.charAt(0) === ';') { generatedLine++; str = str.slice(1); previousGeneratedColumn = 0; } else if (str.charAt(0) === ',') { str = str.slice(1); } else { mapping = {}; mapping.generatedLine = generatedLine; // Generated column. temp = base64VLQ.decode(str); mapping.generatedColumn = previousGeneratedColumn + temp.value; previousGeneratedColumn = mapping.generatedColumn; str = temp.rest; if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { // Original source. temp = base64VLQ.decode(str); if (aSourceRoot) { mapping.source = util.join(aSourceRoot, this._sources.at(previousSource + temp.value)); } else { mapping.source = this._sources.at(previousSource + temp.value); } previousSource += temp.value; str = temp.rest; if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { throw new Error('Found a source, but no line and column'); } // Original line. temp = base64VLQ.decode(str); mapping.originalLine = previousOriginalLine + temp.value; previousOriginalLine = mapping.originalLine; // Lines are stored 0-based mapping.originalLine += 1; str = temp.rest; if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { throw new Error('Found a source and line, but no column'); } // Original column. temp = base64VLQ.decode(str); mapping.originalColumn = previousOriginalColumn + temp.value; previousOriginalColumn = mapping.originalColumn; str = temp.rest; if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { // Original name. temp = base64VLQ.decode(str); mapping.name = this._names.at(previousName + temp.value); previousName += temp.value; str = temp.rest; } } this._generatedMappings.push(mapping); } } }; /** * Returns the original source, line, and column information for the generated * source's line and column positions provided. The only argument is an object * with the following properties: * * - line: The line number in the generated source. * - column: The column number in the generated source. * * and an object is returned with the following properties: * * - source: The original source file, or null. * - line: The line number in the original source, or null. * - column: The column number in the original source, or null. * - name: The original identifier, or null. */ SourceMapConsumer.prototype.originalPositionFor = function SourceMapConsumer_originalPositionFor(aArgs) { // To return the original position, we must first find the mapping for the // given generated position and then return the original position it // points to. Because the mappings are sorted by generated line/column, we // can use binary search to find the best mapping. // To perform a binary search on the mappings, we must be able to compare // two mappings. function compare(mappingA, mappingB) { var cmp = mappingA.generatedLine - mappingB.generatedLine; return cmp === 0 ? mappingA.generatedColumn - mappingB.generatedColumn : cmp; } // This is the mock of the mapping we are looking for: the needle in the // haystack of mappings. var needle = { generatedLine: util.getArg(aArgs, 'line'), generatedColumn: util.getArg(aArgs, 'column') }; if (needle.generatedLine <= 0) { throw new TypeError('Line must be greater than or equal to 1.'); } if (needle.generatedColumn < 0) { throw new TypeError('Column must be greater than or equal to 0.'); } var mapping = binarySearch.search(needle, this._generatedMappings, compare); if (mapping) { return { source: util.getArg(mapping, 'source', null), line: util.getArg(mapping, 'originalLine', null), column: util.getArg(mapping, 'originalColumn', null), name: util.getArg(mapping, 'name', null) }; } return { source: null, line: null, column: null, name: null }; }; exports.SourceMapConsumer = SourceMapConsumer; }); /* -*- 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 */ define('lib/source-map/binary-search', ['require', 'exports', 'module' ], function(require, exports, module) { /** * Recursive implementation of binary search. * * @param aLow Indices here and lower do not contain the needle. * @param aHigh Indices here and higher do not contain the needle. * @param aNeedle The element being searched for. * @param aHaystack The non-empty array being searched. * @param aCompare Function which takes two elements and returns -1, 0, or 1. */ function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { // This function terminates when one of the following is true: // // 1. We find the exact element we are looking for. // // 2. We did not find the exact element, but we can return the next // closest element that is less than that element. // // 3. We did not find the exact element, and there is no next-closest // element which is less than the one we are searching for, so we // return null. var mid = Math.floor((aHigh - aLow) / 2) + aLow; var cmp = aCompare(aNeedle, aHaystack[mid]); if (cmp === 0) { // Found the element we are looking for. return aHaystack[mid]; } else if (cmp > 0) { // aHaystack[mid] is greater than our needle. if (aHigh - mid > 1) { // The element is in the upper half. return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); } // We did not find an exact match, return the next closest one // (termination case 2). return aHaystack[mid]; } else { // aHaystack[mid] is less than our needle. if (mid - aLow > 1) { // The element is in the lower half. return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); } // The exact needle element was not found in this haystack. Determine if // we are in termination case (2) or (3) and return the appropriate thing. return aLow < 0 ? null : aHaystack[aLow]; } } /** * This is an implementation of binary search which will always try and return * the next lowest value checked if there is no exact hit. This is because * mappings between original and generated line/col pairs are single points, * and there is an implicit region between each of them, so a miss just means * that you aren't on the very start of a region. * * @param aNeedle The element you are looking for. * @param aHaystack The array that is being searched. * @param aCompare A function which takes the needle and an element in the * array and returns -1, 0, or 1 depending on whether the needle is less * than, equal to, or greater than the element, respectively. */ exports.search = function search(aNeedle, aHaystack, aCompare) { return aHaystack.length > 0 ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) : null; }; }); /* -*- 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 */ define('lib/source-map/source-node', ['require', 'exports', 'module' , 'lib/source-map/source-map-generator'], function(require, exports, module) { var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; /** * 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. */ function SourceNode(aLine, aColumn, aSource, aChunks) { this.children = []; this.line = aLine; this.column = aColumn; this.source = aSource; if (aChunks != null) this.add(aChunks); } /** * 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 instanceof SourceNode || typeof aChunk === "string") { this.children.push(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) { this.children.forEach(function (chunk) { if (chunk instanceof SourceNode) { chunk.walk(aFn); } else { if (chunk !== '') { aFn(chunk, { source: this.source, line: this.line, column: this.column }); } } }, this); }; /** * 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 instanceof SourceNode) { lastChild.replaceRight(aPattern, aReplacement); } else if (typeof lastChild === 'string') { this.children[this.children.lenth - 1] = lastChild.replace(aPattern, aReplacement); } else { this.children.push(''.replace(aPattern, aReplacement)); } return this; }; /** * 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); this.walk(function (chunk, original) { generated.code += chunk; if (original.source != null && original.line != null && original.column != null) { map.addMapping({ source: original.source, original: { line: original.line, column: original.column }, generated: { line: generated.line, column: generated.column } }); } chunk.split('').forEach(function (char) { if (char === '\n') { generated.line++; generated.column = 0; } else { generated.column++; } }); }); return { code: generated.code, map: map }; }; exports.SourceNode = SourceNode; }); /* -*- Mode: js; js-indent-level: 2; -*- */ /////////////////////////////////////////////////////////////////////////////// window.sourceMap = { SourceMapConsumer: require('lib/source-map/source-map-consumer').SourceMapConsumer, SourceMapGenerator: require('lib/source-map/source-map-generator').SourceMapGenerator, SourceNode: require('lib/source-map/source-node').SourceNode };