diff --git a/third_party/react/JSXTransformer.js b/third_party/react/JSXTransformer.js new file mode 100644 index 000000000..07cc91f02 --- /dev/null +++ b/third_party/react/JSXTransformer.js @@ -0,0 +1,10862 @@ +/** + * JSXTransformer v0.8.0 + */ +!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSXTransformer=e():"undefined"!=typeof global?global.JSXTransformer=e():"undefined"!=typeof self&&(self.JSXTransformer=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o i; ++i) { + if (array.hasOwnProperty(i)) { + if (isValueSet) { + value = callback(value, array[i], i, array); + } + else { + value = array[i]; + isValueSet = true; + } + } + } + + return value; +}; + +// String.prototype.substr - negative index don't work in IE8 +if ('ab'.substr(-1) !== 'b') { + exports.substr = function (str, start, length) { + // did we get a negative start, calculate how much it is from the beginning of the string + if (start < 0) start = str.length + start; + + // call the original function + return str.substr(start, length); + }; +} else { + exports.substr = function (str, start, length) { + return str.substr(start, length); + }; +} + +// String.prototype.trim is supported in IE9 +exports.trim = function (str) { + if (str.trim) return str.trim(); + return str.replace(/^\s+|\s+$/g, ''); +}; + +// Function.prototype.bind is supported in IE9 +exports.bind = function () { + var args = Array.prototype.slice.call(arguments); + var fn = args.shift(); + if (fn.bind) return fn.bind.apply(fn, args); + var self = args.shift(); + return function () { + fn.apply(self, args.concat([Array.prototype.slice.call(arguments)])); + }; +}; + +// Object.create is supported in IE9 +function create(prototype, properties) { + var object; + if (prototype === null) { + object = { '__proto__' : null }; + } + else { + if (typeof prototype !== 'object') { + throw new TypeError( + 'typeof prototype[' + (typeof prototype) + '] != \'object\'' + ); + } + var Type = function () {}; + Type.prototype = prototype; + object = new Type(); + object.__proto__ = prototype; + } + if (typeof properties !== 'undefined' && Object.defineProperties) { + Object.defineProperties(object, properties); + } + return object; +} +exports.create = typeof Object.create === 'function' ? Object.create : create; + +// Object.keys and Object.getOwnPropertyNames is supported in IE9 however +// they do show a description and number property on Error objects +function notObject(object) { + return ((typeof object != "object" && typeof object != "function") || object === null); +} + +function keysShim(object) { + if (notObject(object)) { + throw new TypeError("Object.keys called on a non-object"); + } + + var result = []; + for (var name in object) { + if (hasOwnProperty.call(object, name)) { + result.push(name); + } + } + return result; +} + +// getOwnPropertyNames is almost the same as Object.keys one key feature +// is that it returns hidden properties, since that can't be implemented, +// this feature gets reduced so it just shows the length property on arrays +function propertyShim(object) { + if (notObject(object)) { + throw new TypeError("Object.getOwnPropertyNames called on a non-object"); + } + + var result = keysShim(object); + if (exports.isArray(object) && exports.indexOf(object, 'length') === -1) { + result.push('length'); + } + return result; +} + +var keys = typeof Object.keys === 'function' ? Object.keys : keysShim; +var getOwnPropertyNames = typeof Object.getOwnPropertyNames === 'function' ? + Object.getOwnPropertyNames : propertyShim; + +if (new Error().hasOwnProperty('description')) { + var ERROR_PROPERTY_FILTER = function (obj, array) { + if (toString.call(obj) === '[object Error]') { + array = exports.filter(array, function (name) { + return name !== 'description' && name !== 'number' && name !== 'message'; + }); + } + return array; + }; + + exports.keys = function (object) { + return ERROR_PROPERTY_FILTER(object, keys(object)); + }; + exports.getOwnPropertyNames = function (object) { + return ERROR_PROPERTY_FILTER(object, getOwnPropertyNames(object)); + }; +} else { + exports.keys = keys; + exports.getOwnPropertyNames = getOwnPropertyNames; +} + +// Object.getOwnPropertyDescriptor - supported in IE8 but only on dom elements +function valueObject(value, key) { + return { value: value[key] }; +} + +if (typeof Object.getOwnPropertyDescriptor === 'function') { + try { + Object.getOwnPropertyDescriptor({'a': 1}, 'a'); + exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + } catch (e) { + // IE8 dom element issue - use a try catch and default to valueObject + exports.getOwnPropertyDescriptor = function (value, key) { + try { + return Object.getOwnPropertyDescriptor(value, key); + } catch (e) { + return valueObject(value, key); + } + }; + } +} else { + exports.getOwnPropertyDescriptor = valueObject; +} + +},{}],2:[function(require,module,exports){ +var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var util = require('util'); +var shims = require('_shims'); + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (!util.isString(path)) { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(shims.filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = shims.substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(shims.filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(shims.filter(paths, function(p, index) { + if (!util.isString(p)) { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +},{"__browserify_process":4,"_shims":1,"util":3}],3:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var shims = require('_shims'); + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + shims.forEach(array, function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = shims.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = shims.getOwnPropertyNames(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + + shims.forEach(keys, function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = shims.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (shims.indexOf(ctx.seen, desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = shims.reduce(output, function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return shims.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && objectToString(e) === '[object Error]'; +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.binarySlice === 'function' + ; +} +exports.isBuffer = isBuffer; + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = function(ctor, superCtor) { + ctor.super_ = superCtor; + ctor.prototype = shims.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); +}; + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = shims.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +},{"_shims":1}],4:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; + +process.nextTick = (function () { + var canSetImmediate = typeof window !== 'undefined' + && window.setImmediate; + var canPost = typeof window !== 'undefined' + && window.postMessage && window.addEventListener + ; + + if (canSetImmediate) { + return function (f) { return window.setImmediate(f) }; + } + + if (canPost) { + var queue = []; + window.addEventListener('message', function (ev) { + if (ev.source === window && ev.data === 'process-tick') { + ev.stopPropagation(); + if (queue.length > 0) { + var fn = queue.shift(); + fn(); + } + } + }, true); + + return function nextTick(fn) { + queue.push(fn); + window.postMessage('process-tick', '*'); + }; + } + + return function nextTick(fn) { + setTimeout(fn, 0); + }; +})(); + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +} + +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; + +},{}],5:[function(require,module,exports){ +/* + Copyright (C) 2013 Ariya Hidayat + Copyright (C) 2013 Thaddee Tyl + Copyright (C) 2012 Ariya Hidayat + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*jslint bitwise:true plusplus:true */ +/*global esprima:true, define:true, exports:true, window: true, +throwError: true, generateStatement: true, peek: true, +parseAssignmentExpression: true, parseBlock: true, +parseClassExpression: true, parseClassDeclaration: true, parseExpression: true, +parseForStatement: true, +parseFunctionDeclaration: true, parseFunctionExpression: true, +parseFunctionSourceElements: true, parseVariableIdentifier: true, +parseImportSpecifier: true, +parseLeftHandSideExpression: true, parseParams: true, validateParam: true, +parseSpreadOrAssignmentExpression: true, +parseStatement: true, parseSourceElement: true, parseModuleBlock: true, parseConciseBody: true, +advanceXJSChild: true, isXJSIdentifierStart: true, isXJSIdentifierPart: true, +scanXJSStringLiteral: true, scanXJSIdentifier: true, +parseXJSAttributeValue: true, parseXJSChild: true, parseXJSElement: true, parseXJSExpressionContainer: true, parseXJSEmptyExpression: true, +parseTypeAnnotation: true, parseTypeAnnotatableIdentifier: true, +parseYieldExpression: true +*/ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + FnExprTokens, + Syntax, + PropertyKind, + Messages, + Regex, + SyntaxTreeDelegate, + XHTMLEntities, + ClassPropertyType, + source, + strict, + index, + lineNumber, + lineStart, + length, + delegate, + lookahead, + state, + extra; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8, + RegularExpression: 9, + Template: 10, + XJSIdentifier: 11, + XJSText: 12 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = ''; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + TokenName[Token.XJSIdentifier] = 'XJSIdentifier'; + TokenName[Token.XJSText] = 'XJSText'; + TokenName[Token.RegularExpression] = 'RegularExpression'; + + // A function following one of those tokens is an expression. + FnExprTokens = ["(", "{", "[", "in", "typeof", "instanceof", "new", + "return", "case", "delete", "throw", "void", + // assignment operators + "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", + "&=", "|=", "^=", ",", + // binary/unary operators + "+", "-", "*", "/", "%", "++", "--", "<<", ">>", ">>>", "&", + "|", "^", "!", "~", "&&", "||", "?", ":", "===", "==", ">=", + "<=", "<", ">", "!=", "!=="]; + + Syntax = { + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + AssignmentExpression: 'AssignmentExpression', + BinaryExpression: 'BinaryExpression', + BlockStatement: 'BlockStatement', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ClassHeritage: 'ClassHeritage', + ComprehensionBlock: 'ComprehensionBlock', + ComprehensionExpression: 'ComprehensionExpression', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExportDeclaration: 'ExportDeclaration', + ExportBatchSpecifier: 'ExportBatchSpecifier', + ExportSpecifier: 'ExportSpecifier', + ExpressionStatement: 'ExpressionStatement', + ForInStatement: 'ForInStatement', + ForOfStatement: 'ForOfStatement', + ForStatement: 'ForStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + ImportDeclaration: 'ImportDeclaration', + ImportSpecifier: 'ImportSpecifier', + LabeledStatement: 'LabeledStatement', + Literal: 'Literal', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MethodDefinition: 'MethodDefinition', + ModuleDeclaration: 'ModuleDeclaration', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + SwitchCase: 'SwitchCase', + SwitchStatement: 'SwitchStatement', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + TypeAnnotatedIdentifier: 'TypeAnnotatedIdentifier', + TypeAnnotation: 'TypeAnnotation', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + XJSIdentifier: 'XJSIdentifier', + XJSEmptyExpression: 'XJSEmptyExpression', + XJSExpressionContainer: 'XJSExpressionContainer', + XJSElement: 'XJSElement', + XJSClosingElement: 'XJSClosingElement', + XJSOpeningElement: 'XJSOpeningElement', + XJSAttribute: 'XJSAttribute', + XJSText: 'XJSText', + YieldExpression: 'YieldExpression' + }; + + PropertyKind = { + Data: 1, + Get: 2, + Set: 4 + }; + + ClassPropertyType = { + static: 'static', + prototype: 'prototype' + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedTemplate: 'Unexpected quasi %0', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInFormalsList: 'Invalid left-hand side in formals list', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalDuplicateClassProperty: 'Illegal duplicate property in class definition', + IllegalReturn: 'Illegal return statement', + IllegalYield: 'Illegal yield expression', + IllegalSpread: 'Illegal spread element', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + ParameterAfterRestParameter: 'Rest parameter must be final parameter of an argument list', + DefaultRestParameter: 'Rest parameter can not have a default value', + ElementAfterSpreadElement: 'Spread must be the final element of an element list', + ObjectPatternAsRestParameter: 'Invalid rest parameter', + ObjectPatternAsSpread: 'Invalid spread argument', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode', + NewlineAfterModule: 'Illegal newline after module', + NoFromAfterImport: 'Missing from after import', + InvalidModuleSpecifier: 'Invalid module specifier', + NestedModule: 'Module declaration can not be nested', + NoYieldInGenerator: 'Missing yield in generator', + NoUnintializedConst: 'Const must be initialized', + ComprehensionRequiresBlock: 'Comprehension must have at least one block', + ComprehensionError: 'Comprehension Error', + EachNotAllowed: 'Each is not supported', + InvalidXJSTagName: 'XJS tag name can not be empty', + InvalidXJSAttributeValue: 'XJS value should be either an expression or a quoted XJS text', + ExpectedXJSClosingTag: 'Expected corresponding XJS closing tag for %0' + }; + + // See also tools/generate-unicode-regex.py. + Regex = { + NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'), + NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function isDecimalDigit(ch) { + return (ch >= 48 && ch <= 57); // 0..9 + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + + // 7.2 White Space + + function isWhiteSpace(ch) { + return (ch === 32) || // space + (ch === 9) || // tab + (ch === 0xB) || + (ch === 0xC) || + (ch === 0xA0) || + (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0); + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029); + } + + // 7.6 Identifier Names and Identifiers + + function isIdentifierStart(ch) { + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) + (ch >= 65 && ch <= 90) || // A..Z + (ch >= 97 && ch <= 122) || // a..z + (ch === 92) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); + } + + function isIdentifierPart(ch) { + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) + (ch >= 65 && ch <= 90) || // A..Z + (ch >= 97 && ch <= 122) || // a..z + (ch >= 48 && ch <= 57) || // 0..9 + (ch === 92) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); + } + + // 7.6.1.2 Future Reserved Words + + function isFutureReservedWord(id) { + switch (id) { + case 'class': + case 'enum': + case 'export': + case 'extends': + case 'import': + case 'super': + return true; + default: + return false; + } + } + + function isStrictModeReservedWord(id) { + switch (id) { + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'yield': + case 'let': + return true; + default: + return false; + } + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // 7.6.1.1 Keywords + + function isKeyword(id) { + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + // 'const' is specialized as Keyword in V8. + // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // Some others are from future reserved words. + + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + // 7.4 Comments + + function skipComment() { + var ch, blockComment, lineComment; + + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source.charCodeAt(index); + + if (lineComment) { + ++index; + if (isLineTerminator(ch)) { + lineComment = false; + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + } + } else if (blockComment) { + if (isLineTerminator(ch)) { + if (ch === 13 && source.charCodeAt(index + 1) === 10) { + ++index; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source.charCodeAt(index++); + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + // Block comment ends with '*/' (char #42, char #47). + if (ch === 42) { + ch = source.charCodeAt(index); + if (ch === 47) { + ++index; + blockComment = false; + } + } + } + } else if (ch === 47) { + ch = source.charCodeAt(index + 1); + // Line comment starts with '//' (char #47, char #47). + if (ch === 47) { + index += 2; + lineComment = true; + } else if (ch === 42) { + // Block comment starts with '/*' (char #47, char #42). + index += 2; + blockComment = true; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function scanUnicodeCodePointEscape() { + var ch, code, cu1, cu2; + + ch = source[index]; + code = 0; + + // At least, one hex digit is required. + if (ch === '}') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + while (index < length) { + ch = source[index++]; + if (!isHexDigit(ch)) { + break; + } + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } + + if (code > 0x10FFFF || ch !== '}') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // UTF-16 Encoding + if (code <= 0xFFFF) { + return String.fromCharCode(code); + } + cu1 = ((code - 0x10000) >> 10) + 0xD800; + cu2 = ((code - 0x10000) & 1023) + 0xDC00; + return String.fromCharCode(cu1, cu2); + } + + function getEscapedIdentifier() { + var ch, id; + + ch = source.charCodeAt(index++); + id = String.fromCharCode(ch); + + // '\u' (char #92, char #117) denotes an escaped character. + if (ch === 92) { + if (source.charCodeAt(index) !== 117) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id = ch; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (!isIdentifierPart(ch)) { + break; + } + ++index; + id += String.fromCharCode(ch); + + // '\u' (char #92, char #117) denotes an escaped character. + if (ch === 92) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 117) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + id += ch; + } + } + + return id; + } + + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 92) { + // Blackslash (char #92) marks Unicode escape sequence. + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } + } + + return source.slice(start, index); + } + + function scanIdentifier() { + var start, id, type; + + start = index; + + // Backslash (char #92) starts an escaped character. + id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; + } + + return { + type: type, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + + // 7.7 Punctuators + + function scanPunctuator() { + var start = index, + code = source.charCodeAt(index), + code2, + ch1 = source[index], + ch2, + ch3, + ch4; + + switch (code) { + // Check for most common single-character punctuators. + case 40: // ( open bracket + case 41: // ) close bracket + case 59: // ; semicolon + case 44: // , comma + case 123: // { open curly brace + case 125: // } close curly brace + case 91: // [ + case 93: // ] + case 58: // : + case 63: // ? + case 126: // ~ + ++index; + if (extra.tokenize) { + if (code === 40) { + extra.openParenToken = extra.tokens.length; + } else if (code === 123) { + extra.openCurlyToken = extra.tokens.length; + } + } + return { + type: Token.Punctuator, + value: String.fromCharCode(code), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + + default: + code2 = source.charCodeAt(index + 1); + + // '=' (char #61) marks an assignment or comparison operator. + if (code2 === 61) { + switch (code) { + case 37: // % + case 38: // & + case 42: // *: + case 43: // + + case 45: // - + case 47: // / + case 60: // < + case 62: // > + case 94: // ^ + case 124: // | + index += 2; + return { + type: Token.Punctuator, + value: String.fromCharCode(code) + String.fromCharCode(code2), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + + case 33: // ! + case 61: // = + index += 2; + + // !== and === + if (source.charCodeAt(index) === 61) { + ++index; + } + return { + type: Token.Punctuator, + value: source.slice(start, index), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + default: + break; + } + } + break; + } + + // Peek more characters. + + ch2 = source[index + 1]; + ch3 = source[index + 2]; + ch4 = source[index + 3]; + + // 4-character punctuator: >>>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + if (ch4 === '=') { + index += 4; + return { + type: Token.Punctuator, + value: '>>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + } + + // 3-character punctuators: === !== >>> <<= >>= + + if (ch1 === '>' && ch2 === '>' && ch3 === '>') { + index += 3; + return { + type: Token.Punctuator, + value: '>>>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '<' && ch2 === '<' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '<<=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '>' && ch2 === '>' && ch3 === '=') { + index += 3; + return { + type: Token.Punctuator, + value: '>>=', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '.' && ch2 === '.' && ch3 === '.') { + index += 3; + return { + type: Token.Punctuator, + value: '...', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // Other 2-character punctuators: ++ -- << >> && || + + if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { + index += 2; + return { + type: Token.Punctuator, + value: ch1 + ch2, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '=' && ch2 === '>') { + index += 2; + return { + type: Token.Punctuator, + value: '=>', + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + if (ch1 === '.') { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // 7.8.3 Numeric Literals + + function scanHexLiteral(start) { + var number = ''; + + while (index < length) { + if (!isHexDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanOctalLiteral(prefix, start) { + var number, octal; + + if (isOctalDigit(prefix)) { + octal = true; + number = '0' + source[index++]; + } else { + octal = false; + ++index; + number = ''; + } + + while (index < length) { + if (!isOctalDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (!octal && number.length === 0) { + // only 0o or 0O + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanNumericLiteral() { + var number, start, ch, octal; + + ch = source[index]; + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + // Octal number in ES6 starts with '0o'. + // Binary number in ES6 starts with '0b'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + ++index; + return scanHexLiteral(start); + } + if (ch === 'b' || ch === 'B') { + ++index; + number = ''; + + while (index < length) { + ch = source[index]; + if (ch !== '0' && ch !== '1') { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + // only 0b or 0B + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + if (index < length) { + ch = source.charCodeAt(index); + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + return { + type: Token.NumericLiteral, + value: parseInt(number, 2), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) { + return scanOctalLiteral(ch, start); + } + // decimal number starts with '0' such as '09' is illegal. + if (ch && isDecimalDigit(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === '.') { + number += source[index++]; + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + } else { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + // 7.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, code, unescaped, restore, octal = false; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + str += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } + } + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\x0B'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + str += String.fromCharCode(code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanTemplate() { + var cooked = '', ch, start, terminated, tail, restore, unescaped, code, octal; + + terminated = false; + tail = false; + start = index; + + ++index; + + while (index < length) { + ch = source[index++]; + if (ch === '`') { + tail = true; + terminated = true; + break; + } else if (ch === '$') { + if (source[index] === '{') { + ++index; + terminated = true; + break; + } + cooked += ch; + } else if (ch === '\\') { + ch = source[index++]; + if (!isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'n': + cooked += '\n'; + break; + case 'r': + cooked += '\r'; + break; + case 't': + cooked += '\t'; + break; + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + cooked += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + cooked += unescaped; + } else { + index = restore; + cooked += ch; + } + } + break; + case 'b': + cooked += '\b'; + break; + case 'f': + cooked += '\f'; + break; + case 'v': + cooked += '\v'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + cooked += String.fromCharCode(code); + } else { + cooked += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + cooked += '\n'; + } else { + cooked += ch; + } + } + + if (!terminated) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.Template, + value: { + cooked: cooked, + raw: source.slice(start + 1, index - ((tail) ? 1 : 2)) + }, + tail: tail, + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanTemplateElement(option) { + var startsWith, template; + + lookahead = null; + skipComment(); + + startsWith = (option.head) ? '`' : '}'; + + if (source[index] !== startsWith) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + template = scanTemplate(); + + peek(); + + return template; + } + + function scanRegExp() { + var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; + + lookahead = null; + skipComment(); + + start = index; + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + while (index < length) { + ch = source[index++]; + str += ch; + if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); + } + } + } + + if (!terminated) { + throwError({}, Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + pattern = str.substr(1, str.length - 2); + + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch.charCodeAt(0))) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + for (str += '\\u'; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + } else { + str += '\\'; + } + } else { + flags += ch; + str += ch; + } + } + + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + + peek(); + + + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + return { + literal: str, + value: value, + range: [start, index] + }; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + function advanceSlash() { + var prevToken, + checkToken; + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + prevToken = extra.tokens[extra.tokens.length - 1]; + if (!prevToken) { + // Nothing before that: it cannot be a division. + return scanRegExp(); + } + if (prevToken.type === "Punctuator") { + if (prevToken.value === ")") { + checkToken = extra.tokens[extra.openParenToken - 1]; + if (checkToken && + checkToken.type === "Keyword" && + (checkToken.value === "if" || + checkToken.value === "while" || + checkToken.value === "for" || + checkToken.value === "with")) { + return scanRegExp(); + } + return scanPunctuator(); + } + if (prevToken.value === "}") { + // Dividing a function by anything makes little sense, + // but we have to check for that. + if (extra.tokens[extra.openCurlyToken - 3] && + extra.tokens[extra.openCurlyToken - 3].type === "Keyword") { + // Anonymous function. + checkToken = extra.tokens[extra.openCurlyToken - 4]; + if (!checkToken) { + return scanPunctuator(); + } + } else if (extra.tokens[extra.openCurlyToken - 4] && + extra.tokens[extra.openCurlyToken - 4].type === "Keyword") { + // Named function. + checkToken = extra.tokens[extra.openCurlyToken - 5]; + if (!checkToken) { + return scanRegExp(); + } + } else { + return scanPunctuator(); + } + // checkToken determines whether the function is + // a declaration or an expression. + if (FnExprTokens.indexOf(checkToken.value) >= 0) { + // It is an expression. + return scanPunctuator(); + } + // It is a declaration. + return scanRegExp(); + } + return scanRegExp(); + } + if (prevToken.type === "Keyword") { + return scanRegExp(); + } + return scanPunctuator(); + } + + function advance() { + var ch; + + if (state.inXJSChild) { + return advanceXJSChild(); + } + + skipComment(); + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + range: [index, index] + }; + } + + ch = source.charCodeAt(index); + + // Very common: ( and ) and ; + if (ch === 40 || ch === 41 || ch === 58) { + return scanPunctuator(); + } + + // String literal starts with single quote (#39) or double quote (#34). + if (ch === 39 || ch === 34) { + if (state.inXJSTag) { + return scanXJSStringLiteral(); + } + return scanStringLiteral(); + } + + if (state.inXJSTag && isXJSIdentifierStart(ch)) { + return scanXJSIdentifier(); + } + + if (ch === 96) { + return scanTemplate(); + } + if (isIdentifierStart(ch)) { + return scanIdentifier(); + } + + // Dot (.) char #46 can also start a floating-point number, hence the need + // to check the next character. + if (ch === 46) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(ch)) { + return scanNumericLiteral(); + } + + // Slash (/) char #47 can also start a regex. + if (extra.tokenize && ch === 47) { + return advanceSlash(); + } + + return scanPunctuator(); + } + + function lex() { + var token; + + token = lookahead; + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + lookahead = advance(); + + index = token.range[1]; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + return token; + } + + function peek() { + var pos, line, start; + + pos = index; + line = lineNumber; + start = lineStart; + lookahead = advance(); + index = pos; + lineNumber = line; + lineStart = start; + } + + function lookahead2() { + var adv, pos, line, start, result; + + // If we are collecting the tokens, don't grab the next one yet. + adv = (typeof extra.advance === 'function') ? extra.advance : advance; + + pos = index; + line = lineNumber; + start = lineStart; + + // Scan for the next immediate token. + if (lookahead === null) { + lookahead = adv(); + } + index = lookahead.range[1]; + lineNumber = lookahead.lineNumber; + lineStart = lookahead.lineStart; + + // Grab the token right after. + result = adv(); + index = pos; + lineNumber = line; + lineStart = start; + + return result; + } + + SyntaxTreeDelegate = { + + name: 'SyntaxTree', + + postProcess: function (node) { + return node; + }, + + createArrayExpression: function (elements) { + return { + type: Syntax.ArrayExpression, + elements: elements + }; + }, + + createAssignmentExpression: function (operator, left, right) { + return { + type: Syntax.AssignmentExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBinaryExpression: function (operator, left, right) { + var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : + Syntax.BinaryExpression; + return { + type: type, + operator: operator, + left: left, + right: right + }; + }, + + createBlockStatement: function (body) { + return { + type: Syntax.BlockStatement, + body: body + }; + }, + + createBreakStatement: function (label) { + return { + type: Syntax.BreakStatement, + label: label + }; + }, + + createCallExpression: function (callee, args) { + return { + type: Syntax.CallExpression, + callee: callee, + 'arguments': args + }; + }, + + createCatchClause: function (param, body) { + return { + type: Syntax.CatchClause, + param: param, + body: body + }; + }, + + createConditionalExpression: function (test, consequent, alternate) { + return { + type: Syntax.ConditionalExpression, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createContinueStatement: function (label) { + return { + type: Syntax.ContinueStatement, + label: label + }; + }, + + createDebuggerStatement: function () { + return { + type: Syntax.DebuggerStatement + }; + }, + + createDoWhileStatement: function (body, test) { + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + }, + + createEmptyStatement: function () { + return { + type: Syntax.EmptyStatement + }; + }, + + createExpressionStatement: function (expression) { + return { + type: Syntax.ExpressionStatement, + expression: expression + }; + }, + + createForStatement: function (init, test, update, body) { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + }, + + createForInStatement: function (left, right, body) { + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + }, + + createForOfStatement: function (left, right, body) { + return { + type: Syntax.ForOfStatement, + left: left, + right: right, + body: body, + }; + }, + + createFunctionDeclaration: function (id, params, defaults, body, rest, generator, expression, + returnType) { + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: generator, + expression: expression, + returnType: returnType + }; + }, + + createFunctionExpression: function (id, params, defaults, body, rest, generator, expression, + returnType) { + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: generator, + expression: expression, + returnType: returnType + }; + }, + + createIdentifier: function (name) { + return { + type: Syntax.Identifier, + name: name, + // Only here to initialize the shape of the object to ensure + // that the 'typeAnnotation' key is ordered before others that + // are added later (like 'loc' and 'range'). This just helps + // keep the shape of Identifier nodes consistent with everything + // else. + typeAnnotation: undefined + }; + }, + + createTypeAnnotation: function (typeIdentifier, paramTypes, returnType, isNullable) { + return { + type: Syntax.TypeAnnotation, + id: typeIdentifier, + paramTypes: paramTypes, + returnType: returnType, + isNullable: isNullable + }; + }, + + createTypeAnnotatedIdentifier: function (identifier, annotation) { + return { + type: Syntax.TypeAnnotatedIdentifier, + id: identifier, + annotation: annotation + }; + }, + + createXJSAttribute: function (name, value) { + return { + type: Syntax.XJSAttribute, + name: name, + value: value + }; + }, + + createXJSIdentifier: function (name, namespace) { + return { + type: Syntax.XJSIdentifier, + name: name, + namespace: namespace + }; + }, + + createXJSElement: function (openingElement, closingElement, children) { + return { + type: Syntax.XJSElement, + name: openingElement.name, + selfClosing: openingElement.selfClosing, + openingElement: openingElement, + closingElement: closingElement, + attributes: openingElement.attributes, + children: children + }; + }, + + createXJSEmptyExpression: function () { + return { + type: Syntax.XJSEmptyExpression + }; + }, + + createXJSExpressionContainer: function (expression) { + return { + type: Syntax.XJSExpressionContainer, + expression: expression + }; + }, + + createXJSOpeningElement: function (name, attributes, selfClosing) { + return { + type: Syntax.XJSOpeningElement, + name: name, + selfClosing: selfClosing, + attributes: attributes + }; + }, + + createXJSClosingElement: function (name) { + return { + type: Syntax.XJSClosingElement, + name: name + }; + }, + + createIfStatement: function (test, consequent, alternate) { + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createLabeledStatement: function (label, body) { + return { + type: Syntax.LabeledStatement, + label: label, + body: body + }; + }, + + createLiteral: function (token) { + return { + type: Syntax.Literal, + value: token.value, + raw: source.slice(token.range[0], token.range[1]) + }; + }, + + createMemberExpression: function (accessor, object, property) { + return { + type: Syntax.MemberExpression, + computed: accessor === '[', + object: object, + property: property + }; + }, + + createNewExpression: function (callee, args) { + return { + type: Syntax.NewExpression, + callee: callee, + 'arguments': args + }; + }, + + createObjectExpression: function (properties) { + return { + type: Syntax.ObjectExpression, + properties: properties + }; + }, + + createPostfixExpression: function (operator, argument) { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: false + }; + }, + + createProgram: function (body) { + return { + type: Syntax.Program, + body: body + }; + }, + + createProperty: function (kind, key, value, method, shorthand) { + return { + type: Syntax.Property, + key: key, + value: value, + kind: kind, + method: method, + shorthand: shorthand + }; + }, + + createReturnStatement: function (argument) { + return { + type: Syntax.ReturnStatement, + argument: argument + }; + }, + + createSequenceExpression: function (expressions) { + return { + type: Syntax.SequenceExpression, + expressions: expressions + }; + }, + + createSwitchCase: function (test, consequent) { + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + }, + + createSwitchStatement: function (discriminant, cases) { + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + }, + + createThisExpression: function () { + return { + type: Syntax.ThisExpression + }; + }, + + createThrowStatement: function (argument) { + return { + type: Syntax.ThrowStatement, + argument: argument + }; + }, + + createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: guardedHandlers, + handlers: handlers, + finalizer: finalizer + }; + }, + + createUnaryExpression: function (operator, argument) { + if (operator === '++' || operator === '--') { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: true + }; + } + return { + type: Syntax.UnaryExpression, + operator: operator, + argument: argument + }; + }, + + createVariableDeclaration: function (declarations, kind) { + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + }, + + createVariableDeclarator: function (id, init) { + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + }, + + createWhileStatement: function (test, body) { + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + }, + + createWithStatement: function (object, body) { + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + }, + + createTemplateElement: function (value, tail) { + return { + type: Syntax.TemplateElement, + value: value, + tail: tail + }; + }, + + createTemplateLiteral: function (quasis, expressions) { + return { + type: Syntax.TemplateLiteral, + quasis: quasis, + expressions: expressions + }; + }, + + createSpreadElement: function (argument) { + return { + type: Syntax.SpreadElement, + argument: argument + }; + }, + + createTaggedTemplateExpression: function (tag, quasi) { + return { + type: Syntax.TaggedTemplateExpression, + tag: tag, + quasi: quasi + }; + }, + + createArrowFunctionExpression: function (params, defaults, body, rest, expression) { + return { + type: Syntax.ArrowFunctionExpression, + id: null, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: false, + expression: expression + }; + }, + + createMethodDefinition: function (propertyType, kind, key, value) { + return { + type: Syntax.MethodDefinition, + key: key, + value: value, + kind: kind, + 'static': propertyType === ClassPropertyType.static + }; + }, + + createClassBody: function (body) { + return { + type: Syntax.ClassBody, + body: body + }; + }, + + createClassExpression: function (id, superClass, body) { + return { + type: Syntax.ClassExpression, + id: id, + superClass: superClass, + body: body + }; + }, + + createClassDeclaration: function (id, superClass, body) { + return { + type: Syntax.ClassDeclaration, + id: id, + superClass: superClass, + body: body + }; + }, + + createExportSpecifier: function (id, name) { + return { + type: Syntax.ExportSpecifier, + id: id, + name: name + }; + }, + + createExportBatchSpecifier: function () { + return { + type: Syntax.ExportBatchSpecifier + }; + }, + + createExportDeclaration: function (declaration, specifiers, source) { + return { + type: Syntax.ExportDeclaration, + declaration: declaration, + specifiers: specifiers, + source: source + }; + }, + + createImportSpecifier: function (id, name) { + return { + type: Syntax.ImportSpecifier, + id: id, + name: name + }; + }, + + createImportDeclaration: function (specifiers, kind, source) { + return { + type: Syntax.ImportDeclaration, + specifiers: specifiers, + kind: kind, + source: source + }; + }, + + createYieldExpression: function (argument, delegate) { + return { + type: Syntax.YieldExpression, + argument: argument, + delegate: delegate + }; + }, + + createModuleDeclaration: function (id, source, body) { + return { + type: Syntax.ModuleDeclaration, + id: id, + source: source, + body: body + }; + } + + + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + // Throw an exception + + function throwError(token, messageFormat) { + var error, + args = Array.prototype.slice.call(arguments, 2), + msg = messageFormat.replace( + /%(\d)/g, + function (whole, index) { + assert(index < args.length, 'Message reference must be in range'); + return args[index]; + } + ); + + if (typeof token.lineNumber === 'number') { + error = new Error('Line ' + token.lineNumber + ': ' + msg); + error.index = token.range[0]; + error.lineNumber = token.lineNumber; + error.column = token.range[0] - lineStart + 1; + } else { + error = new Error('Line ' + lineNumber + ': ' + msg); + error.index = index; + error.lineNumber = lineNumber; + error.column = index - lineStart + 1; + } + + error.description = msg; + throw error; + } + + function throwErrorTolerant() { + try { + throwError.apply(null, arguments); + } catch (e) { + if (extra.errors) { + extra.errors.push(e); + } else { + throw e; + } + } + } + + + // Throw an exception because of the token. + + function throwUnexpected(token) { + if (token.type === Token.EOF) { + throwError(token, Messages.UnexpectedEOS); + } + + if (token.type === Token.NumericLiteral) { + throwError(token, Messages.UnexpectedNumber); + } + + if (token.type === Token.StringLiteral) { + throwError(token, Messages.UnexpectedString); + } + + if (token.type === Token.Identifier) { + throwError(token, Messages.UnexpectedIdentifier); + } + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + throwError(token, Messages.UnexpectedReserved); + } else if (strict && isStrictModeReservedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictReservedWord); + return; + } + throwError(token, Messages.UnexpectedToken, token.value); + } + + if (token.type === Token.Template) { + throwError(token, Messages.UnexpectedTemplate, token.value.raw); + } + + // BooleanLiteral, NullLiteral, or Punctuator. + throwError(token, Messages.UnexpectedToken, token.value); + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpected(token); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpected(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + return lookahead.type === Token.Punctuator && lookahead.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + return lookahead.type === Token.Keyword && lookahead.value === keyword; + } + + + // Return true if the next token matches the specified contextual keyword + + function matchContextualKeyword(keyword) { + return lookahead.type === Token.Identifier && lookahead.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var op; + + if (lookahead.type !== Token.Punctuator) { + return false; + } + op = lookahead.value; + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + var line; + + // Catch the very common case first: immediately a semicolon (char #59). + if (source.charCodeAt(index) === 59) { + lex(); + return; + } + + line = lineNumber; + skipComment(); + if (lineNumber !== line) { + return; + } + + if (match(';')) { + lex(); + return; + } + + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpected(lookahead); + } + } + + // Return true if provided expression is LeftHandSideExpression + + function isLeftHandSide(expr) { + return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; + } + + function isAssignableLeftHandSide(expr) { + return isLeftHandSide(expr) || expr.type === Syntax.ObjectPattern || expr.type === Syntax.ArrayPattern; + } + + // 11.1.4 Array Initialiser + + function parseArrayInitialiser() { + var elements = [], blocks = [], filter = null, tmp, possiblecomprehension = true, body; + + expect('['); + while (!match(']')) { + if (lookahead.value === 'for' && + lookahead.type === Token.Keyword) { + if (!possiblecomprehension) { + throwError({}, Messages.ComprehensionError); + } + matchKeyword('for'); + tmp = parseForStatement({ignore_body: true}); + tmp.of = tmp.type === Syntax.ForOfStatement; + tmp.type = Syntax.ComprehensionBlock; + if (tmp.left.kind) { // can't be let or const + throwError({}, Messages.ComprehensionError); + } + blocks.push(tmp); + } else if (lookahead.value === 'if' && + lookahead.type === Token.Keyword) { + if (!possiblecomprehension) { + throwError({}, Messages.ComprehensionError); + } + expectKeyword('if'); + expect('('); + filter = parseExpression(); + expect(')'); + } else if (lookahead.value === ',' && + lookahead.type === Token.Punctuator) { + possiblecomprehension = false; // no longer allowed. + lex(); + elements.push(null); + } else { + tmp = parseSpreadOrAssignmentExpression(); + elements.push(tmp); + if (tmp && tmp.type === Syntax.SpreadElement) { + if (!match(']')) { + throwError({}, Messages.ElementAfterSpreadElement); + } + } else if (!(match(']') || matchKeyword('for') || matchKeyword('if'))) { + expect(','); // this lexes. + possiblecomprehension = false; + } + } + } + + expect(']'); + + if (filter && !blocks.length) { + throwError({}, Messages.ComprehensionRequiresBlock); + } + + if (blocks.length) { + if (elements.length !== 1) { + throwError({}, Messages.ComprehensionError); + } + return { + type: Syntax.ComprehensionExpression, + filter: filter, + blocks: blocks, + body: elements[0] + }; + } + return delegate.createArrayExpression(elements); + } + + // 11.1.5 Object Initialiser + + function parsePropertyFunction(options) { + var previousStrict, previousYieldAllowed, params, defaults, body; + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = options.generator; + params = options.params || []; + defaults = options.defaults || []; + + body = parseConciseBody(); + if (options.name && strict && isRestrictedWord(params[0].name)) { + throwErrorTolerant(options.name, Messages.StrictParamName); + } + if (state.yieldAllowed && !state.yieldFound) { + throwErrorTolerant({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionExpression(null, params, defaults, body, options.rest || null, options.generator, body.type !== Syntax.BlockStatement, + options.returnTypeAnnotation); + } + + + function parsePropertyMethodFunction(options) { + var previousStrict, tmp, method; + + previousStrict = strict; + strict = true; + + tmp = parseParams(); + + if (tmp.stricted) { + throwErrorTolerant(tmp.stricted, tmp.message); + } + + + method = parsePropertyFunction({ + params: tmp.params, + defaults: tmp.defaults, + rest: tmp.rest, + generator: options.generator, + returnTypeAnnotation: tmp.returnTypeAnnotation + }); + + strict = previousStrict; + + return method; + } + + + function parseObjectPropertyKey() { + var token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { + if (strict && token.octal) { + throwErrorTolerant(token, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseObjectProperty() { + var token, key, id, value, param; + + token = lookahead; + + if (token.type === Token.Identifier) { + + id = parseObjectPropertyKey(); + + // Property Assignment: Getter and Setter. + + if (token.value === 'get' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + expect(')'); + return delegate.createProperty('get', key, parsePropertyFunction({ generator: false }), false, false); + } + if (token.value === 'set' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + token = lookahead; + param = [ parseTypeAnnotatableIdentifier() ]; + expect(')'); + return delegate.createProperty('set', key, parsePropertyFunction({ params: param, generator: false, name: token }), false, false); + } + if (match(':')) { + lex(); + return delegate.createProperty('init', id, parseAssignmentExpression(), false, false); + } + if (match('(')) { + return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: false }), true, false); + } + return delegate.createProperty('init', id, id, false, true); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { + if (!match('*')) { + throwUnexpected(token); + } + lex(); + + id = parseObjectPropertyKey(); + + if (!match('(')) { + throwUnexpected(lex()); + } + + return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: true }), true, false); + } + key = parseObjectPropertyKey(); + if (match(':')) { + lex(); + return delegate.createProperty('init', key, parseAssignmentExpression(), false, false); + } + if (match('(')) { + return delegate.createProperty('init', key, parsePropertyMethodFunction({ generator: false }), true, false); + } + throwUnexpected(lex()); + } + + function parseObjectInitialiser() { + var properties = [], property, name, key, kind, map = {}, toString = String; + + expect('{'); + + while (!match('}')) { + property = parseObjectProperty(); + + if (property.key.type === Syntax.Identifier) { + name = property.key.name; + } else { + name = toString(property.key.value); + } + kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; + + key = '$' + name; + if (Object.prototype.hasOwnProperty.call(map, key)) { + if (map[key] === PropertyKind.Data) { + if (strict && kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.StrictDuplicateProperty); + } else if (kind !== PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } + } else { + if (kind === PropertyKind.Data) { + throwErrorTolerant({}, Messages.AccessorDataProperty); + } else if (map[key] & kind) { + throwErrorTolerant({}, Messages.AccessorGetSet); + } + } + map[key] |= kind; + } else { + map[key] = kind; + } + + properties.push(property); + + if (!match('}')) { + expect(','); + } + } + + expect('}'); + + return delegate.createObjectExpression(properties); + } + + function parseTemplateElement(option) { + var token = scanTemplateElement(option); + if (strict && token.octal) { + throwError(token, Messages.StrictOctalLiteral); + } + return delegate.createTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail); + } + + function parseTemplateLiteral() { + var quasi, quasis, expressions; + + quasi = parseTemplateElement({ head: true }); + quasis = [ quasi ]; + expressions = []; + + while (!quasi.tail) { + expressions.push(parseExpression()); + quasi = parseTemplateElement({ head: false }); + quasis.push(quasi); + } + + return delegate.createTemplateLiteral(quasis, expressions); + } + + // 11.1.6 The Grouping Operator + + function parseGroupExpression() { + var expr; + + expect('('); + + ++state.parenthesizedCount; + + state.allowArrowFunction = !state.allowArrowFunction; + expr = parseExpression(); + state.allowArrowFunction = false; + + if (expr.type !== Syntax.ArrowFunctionExpression) { + expect(')'); + } + + return expr; + } + + + // 11.1 Primary Expressions + + function parsePrimaryExpression() { + var type, token; + + token = lookahead; + type = lookahead.type; + + if (type === Token.Identifier) { + lex(); + return delegate.createIdentifier(token.value); + } + + if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + } + return delegate.createLiteral(lex()); + } + + if (type === Token.Keyword) { + if (matchKeyword('this')) { + lex(); + return delegate.createThisExpression(); + } + + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + + if (matchKeyword('class')) { + return parseClassExpression(); + } + + if (matchKeyword('super')) { + lex(); + return delegate.createIdentifier('super'); + } + } + + if (type === Token.BooleanLiteral) { + token = lex(); + token.value = (token.value === 'true'); + return delegate.createLiteral(token); + } + + if (type === Token.NullLiteral) { + token = lex(); + token.value = null; + return delegate.createLiteral(token); + } + + if (match('[')) { + return parseArrayInitialiser(); + } + + if (match('{')) { + return parseObjectInitialiser(); + } + + if (match('(')) { + return parseGroupExpression(); + } + + if (match('/') || match('/=')) { + return delegate.createLiteral(scanRegExp()); + } + + if (type === Token.Template) { + return parseTemplateLiteral(); + } + + if (match('<')) { + return parseXJSElement(); + } + + return throwUnexpected(lex()); + } + + // 11.2 Left-Hand-Side Expressions + + function parseArguments() { + var args = [], arg; + + expect('('); + + if (!match(')')) { + while (index < length) { + arg = parseSpreadOrAssignmentExpression(); + args.push(arg); + + if (match(')')) { + break; + } else if (arg.type === Syntax.SpreadElement) { + throwError({}, Messages.ElementAfterSpreadElement); + } + + expect(','); + } + } + + expect(')'); + + return args; + } + + function parseSpreadOrAssignmentExpression() { + if (match('...')) { + lex(); + return delegate.createSpreadElement(parseAssignmentExpression()); + } + return parseAssignmentExpression(); + } + + function parseNonComputedProperty() { + var token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = parseExpression(); + + expect(']'); + + return expr; + } + + function parseNewExpression() { + var callee, args; + + expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; + + return delegate.createNewExpression(callee, args); + } + + function parseLeftHandSideExpressionAllowCall() { + var expr, args, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + } else if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + } + } + + return expr; + } + + + function parseLeftHandSideExpression() { + var expr, property; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || lookahead.type === Token.Template) { + if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + } + } + + return expr; + } + + // 11.3 Postfix Expressions + + function parsePostfixExpression() { + var expr = parseLeftHandSideExpressionAllowCall(), + token = lookahead; + + if (lookahead.type !== Token.Punctuator) { + return expr; + } + + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = delegate.createPostfixExpression(token.value, expr); + } + + return expr; + } + + // 11.4 Unary Operators + + function parseUnaryExpression() { + var token, expr; + + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + return parsePostfixExpression(); + } + + if (match('++') || match('--')) { + token = lex(); + expr = parseUnaryExpression(); + // 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPrefix); + } + + if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + return delegate.createUnaryExpression(token.value, expr); + } + + if (match('+') || match('-') || match('~') || match('!')) { + token = lex(); + expr = parseUnaryExpression(); + return delegate.createUnaryExpression(token.value, expr); + } + + if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + throwErrorTolerant({}, Messages.StrictDelete); + } + return expr; + } + + return parsePostfixExpression(); + } + + function binaryPrecedence(token, allowIn) { + var prec = 0; + + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; + } + + switch (token.value) { + case '||': + prec = 1; + break; + + case '&&': + prec = 2; + break; + + case '|': + prec = 3; + break; + + case '^': + prec = 4; + break; + + case '&': + prec = 5; + break; + + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; + + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; + + case 'in': + prec = allowIn ? 7 : 0; + break; + + case '<<': + case '>>': + case '>>>': + prec = 8; + break; + + case '+': + case '-': + prec = 9; + break; + + case '*': + case '/': + case '%': + prec = 11; + break; + + default: + break; + } + + return prec; + } + + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators + // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators + + function parseBinaryExpression() { + var expr, token, prec, previousAllowIn, stack, right, operator, left, i; + + previousAllowIn = state.allowIn; + state.allowIn = true; + + expr = parseUnaryExpression(); + + token = lookahead; + prec = binaryPrecedence(token, previousAllowIn); + if (prec === 0) { + return expr; + } + token.prec = prec; + lex(); + + stack = [expr, token, parseUnaryExpression()]; + + while ((prec = binaryPrecedence(lookahead, previousAllowIn)) > 0) { + + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + stack.push(delegate.createBinaryExpression(operator, left, right)); + } + + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + stack.push(parseUnaryExpression()); + } + + state.allowIn = previousAllowIn; + + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + while (i > 1) { + expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + } + return expr; + } + + + // 11.12 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent, alternate; + + expr = parseBinaryExpression(); + + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = parseAssignmentExpression(); + state.allowIn = previousAllowIn; + expect(':'); + alternate = parseAssignmentExpression(); + + expr = delegate.createConditionalExpression(expr, consequent, alternate); + } + + return expr; + } + + // 11.13 Assignment Operators + + function reinterpretAsAssignmentBindingPattern(expr) { + var i, len, property, element; + + if (expr.type === Syntax.ObjectExpression) { + expr.type = Syntax.ObjectPattern; + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (property.kind !== 'init') { + throwError({}, Messages.InvalidLHSInAssignment); + } + reinterpretAsAssignmentBindingPattern(property.value); + } + } else if (expr.type === Syntax.ArrayExpression) { + expr.type = Syntax.ArrayPattern; + for (i = 0, len = expr.elements.length; i < len; i += 1) { + element = expr.elements[i]; + if (element) { + reinterpretAsAssignmentBindingPattern(element); + } + } + } else if (expr.type === Syntax.Identifier) { + if (isRestrictedWord(expr.name)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + } else if (expr.type === Syntax.SpreadElement) { + reinterpretAsAssignmentBindingPattern(expr.argument); + if (expr.argument.type === Syntax.ObjectPattern) { + throwError({}, Messages.ObjectPatternAsSpread); + } + } else { + if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) { + throwError({}, Messages.InvalidLHSInAssignment); + } + } + } + + + function reinterpretAsDestructuredParameter(options, expr) { + var i, len, property, element; + + if (expr.type === Syntax.ObjectExpression) { + expr.type = Syntax.ObjectPattern; + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (property.kind !== 'init') { + throwError({}, Messages.InvalidLHSInFormalsList); + } + reinterpretAsDestructuredParameter(options, property.value); + } + } else if (expr.type === Syntax.ArrayExpression) { + expr.type = Syntax.ArrayPattern; + for (i = 0, len = expr.elements.length; i < len; i += 1) { + element = expr.elements[i]; + if (element) { + reinterpretAsDestructuredParameter(options, element); + } + } + } else if (expr.type === Syntax.Identifier) { + validateParam(options, expr, expr.name); + } else { + if (expr.type !== Syntax.MemberExpression) { + throwError({}, Messages.InvalidLHSInFormalsList); + } + } + } + + function reinterpretAsCoverFormalsList(expressions) { + var i, len, param, params, defaults, defaultCount, options, rest; + + params = []; + defaults = []; + defaultCount = 0; + rest = null; + options = { + paramSet: {} + }; + + for (i = 0, len = expressions.length; i < len; i += 1) { + param = expressions[i]; + if (param.type === Syntax.Identifier) { + params.push(param); + defaults.push(null); + validateParam(options, param, param.name); + } else if (param.type === Syntax.ObjectExpression || param.type === Syntax.ArrayExpression) { + reinterpretAsDestructuredParameter(options, param); + params.push(param); + defaults.push(null); + } else if (param.type === Syntax.SpreadElement) { + assert(i === len - 1, "It is guaranteed that SpreadElement is last element by parseExpression"); + reinterpretAsDestructuredParameter(options, param.argument); + rest = param.argument; + } else if (param.type === Syntax.AssignmentExpression) { + params.push(param.left); + defaults.push(param.right); + ++defaultCount; + } else { + return null; + } + } + + if (options.firstRestricted) { + throwError(options.firstRestricted, options.message); + } + if (options.stricted) { + throwErrorTolerant(options.stricted, options.message); + } + + if (defaultCount === 0) { + defaults = []; + } + + return { params: params, defaults: defaults, rest: rest }; + } + + function parseArrowFunctionExpression(options) { + var previousStrict, previousYieldAllowed, body; + + expect('=>'); + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + strict = true; + state.yieldAllowed = false; + body = parseConciseBody(); + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createArrowFunctionExpression(options.params, options.defaults, body, options.rest, body.type !== Syntax.BlockStatement); + } + + function parseAssignmentExpression() { + var expr, token, params, oldParenthesizedCount; + + if (matchKeyword('yield')) { + return parseYieldExpression(); + } + + oldParenthesizedCount = state.parenthesizedCount; + + if (match('(')) { + token = lookahead2(); + if ((token.type === Token.Punctuator && token.value === ')') || token.value === '...') { + params = parseParams(); + if (!match('=>')) { + throwUnexpected(lex()); + } + return parseArrowFunctionExpression(params); + } + } + + token = lookahead; + expr = parseConditionalExpression(); + + if (match('=>') && expr.type === Syntax.Identifier) { + if (state.parenthesizedCount === oldParenthesizedCount || state.parenthesizedCount === (oldParenthesizedCount + 1)) { + if (isRestrictedWord(expr.name)) { + throwError({}, Messages.StrictParamName); + } + return parseArrowFunctionExpression({ params: [ expr ], defaults: [], rest: null }); + } + } + + if (matchAssign()) { + // 11.13.1 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant(token, Messages.StrictLHSAssignment); + } + + // ES.next draf 11.13 Runtime Semantics step 1 + if (match('=') && (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression)) { + reinterpretAsAssignmentBindingPattern(expr); + } else if (!isLeftHandSide(expr)) { + throwError({}, Messages.InvalidLHSInAssignment); + } + + expr = delegate.createAssignmentExpression(lex().value, expr, parseAssignmentExpression()); + } + + return expr; + } + + // 11.14 Comma Operator + + function parseExpression() { + var expr, expressions, sequence, coverFormalsList, spreadFound, token; + + expr = parseAssignmentExpression(); + expressions = [ expr ]; + + if (match(',')) { + while (index < length) { + if (!match(',')) { + break; + } + + lex(); + expr = parseSpreadOrAssignmentExpression(); + expressions.push(expr); + + if (expr.type === Syntax.SpreadElement) { + spreadFound = true; + if (!match(')')) { + throwError({}, Messages.ElementAfterSpreadElement); + } + break; + } + } + + sequence = delegate.createSequenceExpression(expressions); + } + + if (state.allowArrowFunction && match(')')) { + token = lookahead2(); + if (token.value === '=>') { + lex(); + + state.allowArrowFunction = false; + expr = expressions; + coverFormalsList = reinterpretAsCoverFormalsList(expr); + if (coverFormalsList) { + return parseArrowFunctionExpression(coverFormalsList); + } + + throwUnexpected(token); + } + } + + if (spreadFound) { + throwError({}, Messages.IllegalSpread); + } + + return sequence || expr; + } + + // 12.1 Block + + function parseStatementList() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseSourceElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseBlock() { + var block; + + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return delegate.createBlockStatement(block); + } + + // 12.2 Variable Statement + + function parseTypeAnnotation(dontExpectColon) { + var typeIdentifier = null, paramTypes = null, returnType = null, + isNullable = false; + + if (!dontExpectColon) { + expect(':'); + } + + if (match('?')) { + lex(); + isNullable = true; + } + + if (lookahead.type === Token.Identifier) { + typeIdentifier = parseVariableIdentifier(); + } + + if (match('(')) { + lex(); + paramTypes = []; + while (lookahead.type === Token.Identifier || match('?')) { + paramTypes.push(parseTypeAnnotation(true)); + if (!match(')')) { + expect(','); + } + } + expect(')'); + expect('=>'); + + if (matchKeyword('void')) { + lex(); + } else { + returnType = parseTypeAnnotation(true); + } + } + + return delegate.createTypeAnnotation( + typeIdentifier, + paramTypes, + returnType, + isNullable + ); + } + + function parseVariableIdentifier() { + var token = lex(); + + if (token.type !== Token.Identifier) { + throwUnexpected(token); + } + + return delegate.createIdentifier(token.value); + } + + function parseTypeAnnotatableIdentifier() { + var ident = parseVariableIdentifier(); + + if (match(':')) { + return delegate.createTypeAnnotatedIdentifier(ident, parseTypeAnnotation()); + } + + return ident; + } + + function parseVariableDeclaration(kind) { + var id, + init = null; + if (match('{')) { + id = parseObjectInitialiser(); + reinterpretAsAssignmentBindingPattern(id); + } else if (match('[')) { + id = parseArrayInitialiser(); + reinterpretAsAssignmentBindingPattern(id); + } else { + id = state.allowKeyword ? parseNonComputedProperty() : parseTypeAnnotatableIdentifier(); + // 12.2.1 + if (strict && isRestrictedWord(id.name)) { + throwErrorTolerant({}, Messages.StrictVarName); + } + } + + if (kind === 'const') { + if (!match('=')) { + throwError({}, Messages.NoUnintializedConst); + } + expect('='); + init = parseAssignmentExpression(); + } else if (match('=')) { + lex(); + init = parseAssignmentExpression(); + } + + return delegate.createVariableDeclarator(id, init); + } + + function parseVariableDeclarationList(kind) { + var list = []; + + do { + list.push(parseVariableDeclaration(kind)); + if (!match(',')) { + break; + } + lex(); + } while (index < length); + + return list; + } + + function parseVariableStatement() { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList(); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, 'var'); + } + + // kind may be `const` or `let` + // Both are experimental and not in the specification yet. + // see http://wiki.ecmascript.org/doku.php?id=harmony:const + // and http://wiki.ecmascript.org/doku.php?id=harmony:let + function parseConstLetDeclaration(kind) { + var declarations; + + expectKeyword(kind); + + declarations = parseVariableDeclarationList(kind); + + consumeSemicolon(); + + return delegate.createVariableDeclaration(declarations, kind); + } + + // http://wiki.ecmascript.org/doku.php?id=harmony:modules + + function parseModuleDeclaration() { + var id, src, body; + + lex(); // 'module' + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterModule); + } + + switch (lookahead.type) { + + case Token.StringLiteral: + id = parsePrimaryExpression(); + body = parseModuleBlock(); + src = null; + break; + + case Token.Identifier: + id = parseVariableIdentifier(); + body = null; + if (!matchContextualKeyword('from')) { + throwUnexpected(lex()); + } + lex(); + src = parsePrimaryExpression(); + if (src.type !== Syntax.Literal) { + throwError({}, Messages.InvalidModuleSpecifier); + } + break; + } + + consumeSemicolon(); + return delegate.createModuleDeclaration(id, src, body); + } + + function parseExportBatchSpecifier() { + expect('*'); + return delegate.createExportBatchSpecifier(); + } + + function parseExportSpecifier() { + var id, name = null; + + id = parseVariableIdentifier(); + if (matchContextualKeyword('as')) { + lex(); + name = parseNonComputedProperty(); + } + + return delegate.createExportSpecifier(id, name); + } + + function parseExportDeclaration() { + var previousAllowKeyword, decl, def, src, specifiers; + + expectKeyword('export'); + + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'let': + case 'const': + case 'var': + case 'class': + case 'function': + return delegate.createExportDeclaration(parseSourceElement(), null, null); + } + } + + if (isIdentifierName(lookahead)) { + previousAllowKeyword = state.allowKeyword; + state.allowKeyword = true; + decl = parseVariableDeclarationList('let'); + state.allowKeyword = previousAllowKeyword; + return delegate.createExportDeclaration(decl, null, null); + } + + specifiers = []; + src = null; + + if (match('*')) { + specifiers.push(parseExportBatchSpecifier()); + } else { + expect('{'); + do { + specifiers.push(parseExportSpecifier()); + } while (match(',') && lex()); + expect('}'); + } + + if (matchContextualKeyword('from')) { + lex(); + src = parsePrimaryExpression(); + if (src.type !== Syntax.Literal) { + throwError({}, Messages.InvalidModuleSpecifier); + } + } + + consumeSemicolon(); + + return delegate.createExportDeclaration(null, specifiers, src); + } + + function parseImportDeclaration() { + var specifiers, kind, src; + + expectKeyword('import'); + specifiers = []; + + if (isIdentifierName(lookahead)) { + kind = 'default'; + specifiers.push(parseImportSpecifier()); + + if (!matchContextualKeyword('from')) { + throwError({}, Messages.NoFromAfterImport); + } + lex(); + } else if (match('{')) { + kind = 'named'; + lex(); + do { + specifiers.push(parseImportSpecifier()); + } while (match(',') && lex()); + expect('}'); + + if (!matchContextualKeyword('from')) { + throwError({}, Messages.NoFromAfterImport); + } + lex(); + } + + src = parsePrimaryExpression(); + if (src.type !== Syntax.Literal) { + throwError({}, Messages.InvalidModuleSpecifier); + } + + consumeSemicolon(); + + return delegate.createImportDeclaration(specifiers, kind, src); + } + + function parseImportSpecifier() { + var id, name = null; + + id = parseNonComputedProperty(); + if (matchContextualKeyword('as')) { + lex(); + name = parseVariableIdentifier(); + } + + return delegate.createImportSpecifier(id, name); + } + + // 12.3 Empty Statement + + function parseEmptyStatement() { + expect(';'); + return delegate.createEmptyStatement(); + } + + // 12.4 Expression Statement + + function parseExpressionStatement() { + var expr = parseExpression(); + consumeSemicolon(); + return delegate.createExpressionStatement(expr); + } + + // 12.5 If statement + + function parseIfStatement() { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return delegate.createIfStatement(test, consequent, alternate); + } + + // 12.6 Iteration Statements + + function parseDoWhileStatement() { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return delegate.createDoWhileStatement(body, test); + } + + function parseWhileStatement() { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return delegate.createWhileStatement(test, body); + } + + function parseForVariableDeclaration() { + var token = lex(), + declarations = parseVariableDeclarationList(); + + return delegate.createVariableDeclaration(declarations, token.value); + } + + function parseForStatement(opts) { + var init, test, update, left, right, body, operator, oldInIteration; + init = test = update = null; + expectKeyword('for'); + + // http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators&s=each + if (matchContextualKeyword("each")) { + throwError({}, Messages.EachNotAllowed); + } + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) { + state.allowIn = false; + init = parseForVariableDeclaration(); + state.allowIn = true; + + if (init.declarations.length === 1) { + if (matchKeyword('in') || matchContextualKeyword('of')) { + operator = lookahead; + if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) { + lex(); + left = init; + right = parseExpression(); + init = null; + } + } + } + } else { + state.allowIn = false; + init = parseExpression(); + state.allowIn = true; + + if (matchContextualKeyword('of')) { + operator = lex(); + left = init; + right = parseExpression(); + init = null; + } else if (matchKeyword('in')) { + // LeftHandSideExpression + if (!isAssignableLeftHandSide(init)) { + throwError({}, Messages.InvalidLHSInForIn); + } + operator = lex(); + left = init; + right = parseExpression(); + init = null; + } + } + + if (typeof left === 'undefined') { + expect(';'); + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + if (!(opts !== undefined && opts.ignore_body)) { + body = parseStatement(); + } + + state.inIteration = oldInIteration; + + if (typeof left === 'undefined') { + return delegate.createForStatement(init, test, update, body); + } + + if (operator.value === 'in') { + return delegate.createForInStatement(left, right, body); + } + return delegate.createForOfStatement(left, right, body); + } + + // 12.7 The continue statement + + function parseContinueStatement() { + var label = null, key; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source.charCodeAt(index) === 59) { + lex(); + + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (peekLineTerminator()) { + if (!state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError({}, Messages.IllegalContinue); + } + + return delegate.createContinueStatement(label); + } + + // 12.8 The break statement + + function parseBreakStatement() { + var label = null, key; + + expectKeyword('break'); + + // Catch the very common case first: immediately a semicolon (char #59). + if (source.charCodeAt(index) === 59) { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (peekLineTerminator()) { + if (!(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError({}, Messages.IllegalBreak); + } + + return delegate.createBreakStatement(label); + } + + // 12.9 The return statement + + function parseReturnStatement() { + var argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + throwErrorTolerant({}, Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source.charCodeAt(index) === 32) { + if (isIdentifierStart(source.charCodeAt(index + 1))) { + argument = parseExpression(); + consumeSemicolon(); + return delegate.createReturnStatement(argument); + } + } + + if (peekLineTerminator()) { + return delegate.createReturnStatement(null); + } + + if (!match(';')) { + if (!match('}') && lookahead.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return delegate.createReturnStatement(argument); + } + + // 12.10 The with statement + + function parseWithStatement() { + var object, body; + + if (strict) { + throwErrorTolerant({}, Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return delegate.createWithStatement(object, body); + } + + // 12.10 The swith statement + + function parseSwitchCase() { + var test, + consequent = [], + sourceElement; + + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (index < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + consequent.push(sourceElement); + } + + return delegate.createSwitchCase(test, consequent); + } + + function parseSwitchStatement() { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + cases = []; + + if (match('}')) { + lex(); + return delegate.createSwitchStatement(discriminant, cases); + } + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (index < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError({}, Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return delegate.createSwitchStatement(discriminant, cases); + } + + // 12.13 The throw statement + + function parseThrowStatement() { + var argument; + + expectKeyword('throw'); + + if (peekLineTerminator()) { + throwError({}, Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return delegate.createThrowStatement(argument); + } + + // 12.14 The try statement + + function parseCatchClause() { + var param, body; + + expectKeyword('catch'); + + expect('('); + if (match(')')) { + throwUnexpected(lookahead); + } + + param = parseExpression(); + // 12.14.1 + if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) { + throwErrorTolerant({}, Messages.StrictCatchVariable); + } + + expect(')'); + body = parseBlock(); + return delegate.createCatchClause(param, body); + } + + function parseTryStatement() { + var block, handlers = [], finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handlers.push(parseCatchClause()); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (handlers.length === 0 && !finalizer) { + throwError({}, Messages.NoCatchOrFinally); + } + + return delegate.createTryStatement(block, [], handlers, finalizer); + } + + // 12.15 The debugger statement + + function parseDebuggerStatement() { + expectKeyword('debugger'); + + consumeSemicolon(); + + return delegate.createDebuggerStatement(); + } + + // 12 Statements + + function parseStatement() { + var type = lookahead.type, + expr, + labeledBody, + key; + + if (type === Token.EOF) { + throwUnexpected(lookahead); + } + + if (type === Token.Punctuator) { + switch (lookahead.value) { + case ';': + return parseEmptyStatement(); + case '{': + return parseBlock(); + case '(': + return parseExpressionStatement(); + default: + break; + } + } + + if (type === Token.Keyword) { + switch (lookahead.value) { + case 'break': + return parseBreakStatement(); + case 'continue': + return parseContinueStatement(); + case 'debugger': + return parseDebuggerStatement(); + case 'do': + return parseDoWhileStatement(); + case 'for': + return parseForStatement(); + case 'function': + return parseFunctionDeclaration(); + case 'class': + return parseClassDeclaration(); + case 'if': + return parseIfStatement(); + case 'return': + return parseReturnStatement(); + case 'switch': + return parseSwitchStatement(); + case 'throw': + return parseThrowStatement(); + case 'try': + return parseTryStatement(); + case 'var': + return parseVariableStatement(); + case 'while': + return parseWhileStatement(); + case 'with': + return parseWithStatement(); + default: + break; + } + } + + expr = parseExpression(); + + // 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError({}, Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[key] = true; + labeledBody = parseStatement(); + delete state.labelSet[key]; + return delegate.createLabeledStatement(expr, labeledBody); + } + + consumeSemicolon(); + + return delegate.createExpressionStatement(expr); + } + + // 13 Function Definition + + function parseConciseBody() { + if (match('{')) { + return parseFunctionSourceElements(); + } + return parseAssignmentExpression(); + } + + function parseFunctionSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesizedCount; + + expect('{'); + + while (index < length) { + if (lookahead.type !== Token.StringLiteral) { + break; + } + token = lookahead; + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + oldParenthesizedCount = state.parenthesizedCount; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + state.parenthesizedCount = 0; + + while (index < length) { + if (match('}')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + state.parenthesizedCount = oldParenthesizedCount; + + return delegate.createBlockStatement(sourceElements); + } + + function validateParam(options, param, name) { + var key = '$' + name; + if (strict) { + if (isRestrictedWord(name)) { + options.stricted = param; + options.message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } else if (!options.firstRestricted) { + if (isRestrictedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.firstRestricted = param; + options.message = Messages.StrictParamDupe; + } + } + options.paramSet[key] = true; + } + + function parseParam(options) { + var token, rest, param, def; + + token = lookahead; + if (token.value === '...') { + token = lex(); + rest = true; + } + + if (match('[')) { + param = parseArrayInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else if (match('{')) { + if (rest) { + throwError({}, Messages.ObjectPatternAsRestParameter); + } + param = parseObjectInitialiser(); + reinterpretAsDestructuredParameter(options, param); + } else { + // Typing rest params is awkward, so punting on that for now + param = rest + ? parseVariableIdentifier() + : parseTypeAnnotatableIdentifier(); + validateParam(options, token, token.value); + if (match('=')) { + if (rest) { + throwErrorTolerant(lookahead, Messages.DefaultRestParameter); + } + lex(); + def = parseAssignmentExpression(); + ++options.defaultCount; + } + } + + if (rest) { + if (!match(')')) { + throwError({}, Messages.ParameterAfterRestParameter); + } + options.rest = param; + return false; + } + + options.params.push(param); + options.defaults.push(def); + return !match(')'); + } + + function parseParams(firstRestricted) { + var options; + + options = { + params: [], + defaultCount: 0, + defaults: [], + rest: null, + firstRestricted: firstRestricted + }; + + expect('('); + + if (!match(')')) { + options.paramSet = {}; + while (index < length) { + if (!parseParam(options)) { + break; + } + expect(','); + } + } + + expect(')'); + + if (options.defaultCount === 0) { + options.defaults = []; + } + + if (match(':')) { + options.returnTypeAnnotation = parseTypeAnnotation(); + } + + return options; + } + + function parseFunctionDeclaration() { + var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator, expression; + + expectKeyword('function'); + + generator = false; + if (match('*')) { + lex(); + generator = true; + } + + token = lookahead; + + id = parseVariableIdentifier(); + + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = generator; + + // here we redo some work in order to set 'expression' + expression = !match('{'); + body = parseConciseBody(); + + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && tmp.stricted) { + throwErrorTolerant(tmp.stricted, message); + } + if (state.yieldAllowed && !state.yieldFound) { + throwErrorTolerant({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionDeclaration(id, tmp.params, tmp.defaults, body, tmp.rest, generator, expression, + tmp.returnTypeAnnotation); + } + + function parseFunctionExpression() { + var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator, expression; + + expectKeyword('function'); + + generator = false; + + if (match('*')) { + lex(); + generator = true; + } + + if (!match('(')) { + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + tmp = parseParams(firstRestricted); + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = generator; + + // here we redo some work in order to set 'expression' + expression = !match('{'); + body = parseConciseBody(); + + if (strict && firstRestricted) { + throwError(firstRestricted, message); + } + if (strict && tmp.stricted) { + throwErrorTolerant(tmp.stricted, message); + } + if (state.yieldAllowed && !state.yieldFound) { + throwErrorTolerant({}, Messages.NoYieldInGenerator); + } + strict = previousStrict; + state.yieldAllowed = previousYieldAllowed; + + return delegate.createFunctionExpression(id, tmp.params, tmp.defaults, body, tmp.rest, generator, expression, + tmp.returnTypeAnnotation); + } + + function parseYieldExpression() { + var delegateFlag, expr, previousYieldAllowed; + + expectKeyword('yield'); + + if (!state.yieldAllowed) { + throwErrorTolerant({}, Messages.IllegalYield); + } + + delegateFlag = false; + if (match('*')) { + lex(); + delegateFlag = true; + } + + // It is a Syntax Error if any AssignmentExpression Contains YieldExpression. + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + expr = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + state.yieldFound = true; + + return delegate.createYieldExpression(expr, delegateFlag); + } + + // 14 Classes + + function parseMethodDefinition(existingPropNames) { + var token, key, param, propType, isValidDuplicateProp = false; + + if (lookahead.value === 'static') { + propType = ClassPropertyType.static; + lex(); + } else { + propType = ClassPropertyType.prototype; + } + + if (match('*')) { + lex(); + return delegate.createMethodDefinition( + propType, + '', + parseObjectPropertyKey(), + parsePropertyMethodFunction({ generator: true }) + ); + } + + token = lookahead; + key = parseObjectPropertyKey(); + + if (token.value === 'get' && !match('(')) { + key = parseObjectPropertyKey(); + + // It is a syntax error if any other properties have a name + // duplicating this one unless they are a setter + if (existingPropNames[propType].hasOwnProperty(key.name)) { + isValidDuplicateProp = + // There isn't already a getter for this prop + existingPropNames[propType][key.name].get === undefined + // There isn't already a data prop by this name + && existingPropNames[propType][key.name].data === undefined + // The only existing prop by this name is a setter + && existingPropNames[propType][key.name].set !== undefined; + if (!isValidDuplicateProp) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].get = true; + + expect('('); + expect(')'); + return delegate.createMethodDefinition( + propType, + 'get', + key, + parsePropertyFunction({ generator: false }) + ); + } + if (token.value === 'set' && !match('(')) { + key = parseObjectPropertyKey(); + + // It is a syntax error if any other properties have a name + // duplicating this one unless they are a getter + if (existingPropNames[propType].hasOwnProperty(key.name)) { + isValidDuplicateProp = + // There isn't already a setter for this prop + existingPropNames[propType][key.name].set === undefined + // There isn't already a data prop by this name + && existingPropNames[propType][key.name].data === undefined + // The only existing prop by this name is a getter + && existingPropNames[propType][key.name].get !== undefined; + if (!isValidDuplicateProp) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].set = true; + + expect('('); + token = lookahead; + param = [ parseTypeAnnotatableIdentifier() ]; + expect(')'); + return delegate.createMethodDefinition( + propType, + 'set', + key, + parsePropertyFunction({ params: param, generator: false, name: token }) + ); + } + + // It is a syntax error if any other properties have the same name as a + // non-getter, non-setter method + if (existingPropNames[propType].hasOwnProperty(key.name)) { + throwError(key, Messages.IllegalDuplicateClassProperty); + } else { + existingPropNames[propType][key.name] = {}; + } + existingPropNames[propType][key.name].data = true; + + return delegate.createMethodDefinition( + propType, + '', + key, + parsePropertyMethodFunction({ generator: false }) + ); + } + + function parseClassElement(existingProps) { + if (match(';')) { + lex(); + return; + } + return parseMethodDefinition(existingProps); + } + + function parseClassBody() { + var classElement, classElements = [], existingProps = {}; + + existingProps[ClassPropertyType.static] = {}; + existingProps[ClassPropertyType.prototype] = {}; + + expect('{'); + + while (index < length) { + if (match('}')) { + break; + } + classElement = parseClassElement(existingProps); + + if (typeof classElement !== 'undefined') { + classElements.push(classElement); + } + } + + expect('}'); + + return delegate.createClassBody(classElements); + } + + function parseClassExpression() { + var id, previousYieldAllowed, superClass = null; + + expectKeyword('class'); + + if (!matchKeyword('extends') && !match('{')) { + id = parseVariableIdentifier(); + } + + if (matchKeyword('extends')) { + expectKeyword('extends'); + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + superClass = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + } + + return delegate.createClassExpression(id, superClass, parseClassBody()); + } + + function parseClassDeclaration() { + var id, previousYieldAllowed, superClass = null; + + expectKeyword('class'); + + id = parseVariableIdentifier(); + + if (matchKeyword('extends')) { + expectKeyword('extends'); + previousYieldAllowed = state.yieldAllowed; + state.yieldAllowed = false; + superClass = parseAssignmentExpression(); + state.yieldAllowed = previousYieldAllowed; + } + + return delegate.createClassDeclaration(id, superClass, parseClassBody()); + } + + // 15 Program + + function matchModuleDeclaration() { + var id; + if (matchContextualKeyword('module')) { + id = lookahead2(); + return id.type === Token.StringLiteral || id.type === Token.Identifier; + } + return false; + } + + function parseSourceElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'const': + case 'let': + return parseConstLetDeclaration(lookahead.value); + case 'function': + return parseFunctionDeclaration(); + case 'export': + return parseExportDeclaration(); + case 'import': + return parseImportDeclaration(); + default: + return parseStatement(); + } + } + + if (matchModuleDeclaration()) { + throwError({}, Messages.NestedModule); + } + + if (lookahead.type !== Token.EOF) { + return parseStatement(); + } + } + + function parseProgramElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'export': + return parseExportDeclaration(); + case 'import': + return parseImportDeclaration(); + } + } + + if (matchModuleDeclaration()) { + return parseModuleDeclaration(); + } + + return parseSourceElement(); + } + + function parseProgramElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; + + while (index < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseProgramElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.range[0] + 1, token.range[1] - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (index < length) { + sourceElement = parseProgramElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } + + function parseModuleElement() { + return parseSourceElement(); + } + + function parseModuleElements() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseModuleElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseModuleBlock() { + var block; + + expect('{'); + + block = parseModuleElements(); + + expect('}'); + + return delegate.createBlockStatement(block); + } + + function parseProgram() { + var body; + strict = false; + peek(); + body = parseProgramElements(); + return delegate.createProgram(body); + } + + // The following functions are needed only when the option to preserve + // the comments is active. + + function addComment(type, value, start, end, loc) { + assert(typeof start === 'number', 'Comment must have valid position'); + + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (extra.comments.length > 0) { + if (extra.comments[extra.comments.length - 1].range[1] > start) { + return; + } + } + + extra.comments.push({ + type: type, + value: value, + range: [start, end], + loc: loc + }); + } + + function scanComment() { + var comment, ch, loc, start, blockComment, lineComment; + + comment = ''; + blockComment = false; + lineComment = false; + + while (index < length) { + ch = source[index]; + + if (lineComment) { + ch = source[index++]; + if (isLineTerminator(ch.charCodeAt(0))) { + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + lineComment = false; + addComment('Line', comment, start, index - 1, loc); + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + comment = ''; + } else if (index >= length) { + lineComment = false; + comment += ch; + loc.end = { + line: lineNumber, + column: length - lineStart + }; + addComment('Line', comment, start, length, loc); + } else { + comment += ch; + } + } else if (blockComment) { + if (isLineTerminator(ch.charCodeAt(0))) { + if (ch === '\r' && source[index + 1] === '\n') { + ++index; + comment += '\r\n'; + } else { + comment += ch; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + ch = source[index++]; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + comment += ch; + if (ch === '*') { + ch = source[index]; + if (ch === '/') { + comment = comment.substr(0, comment.length - 1); + blockComment = false; + ++index; + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + comment = ''; + } + } + } + } else if (ch === '/') { + ch = source[index + 1]; + if (ch === '/') { + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + start = index; + index += 2; + lineComment = true; + if (index >= length) { + loc.end = { + line: lineNumber, + column: index - lineStart + }; + lineComment = false; + addComment('Line', comment, start, index, loc); + } + } else if (ch === '*') { + start = index; + index += 2; + blockComment = true; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else { + break; + } + } else if (isWhiteSpace(ch.charCodeAt(0))) { + ++index; + } else if (isLineTerminator(ch.charCodeAt(0))) { + ++index; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + ++lineNumber; + lineStart = index; + } else { + break; + } + } + } + + function filterCommentLocation() { + var i, entry, comment, comments = []; + + for (i = 0; i < extra.comments.length; ++i) { + entry = extra.comments[i]; + comment = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + comment.range = entry.range; + } + if (extra.loc) { + comment.loc = entry.loc; + } + comments.push(comment); + } + + extra.comments = comments; + } + + // 16 XJS + + XHTMLEntities = { + quot: '\u0022', + amp: '&', + apos: "\u0027", + lt: "<", + gt: ">", + nbsp: "\u00A0", + iexcl: "\u00A1", + cent: "\u00A2", + pound: "\u00A3", + curren: "\u00A4", + yen: "\u00A5", + brvbar: "\u00A6", + sect: "\u00A7", + uml: "\u00A8", + copy: "\u00A9", + ordf: "\u00AA", + laquo: "\u00AB", + not: "\u00AC", + shy: "\u00AD", + reg: "\u00AE", + macr: "\u00AF", + deg: "\u00B0", + plusmn: "\u00B1", + sup2: "\u00B2", + sup3: "\u00B3", + acute: "\u00B4", + micro: "\u00B5", + para: "\u00B6", + middot: "\u00B7", + cedil: "\u00B8", + sup1: "\u00B9", + ordm: "\u00BA", + raquo: "\u00BB", + frac14: "\u00BC", + frac12: "\u00BD", + frac34: "\u00BE", + iquest: "\u00BF", + Agrave: "\u00C0", + Aacute: "\u00C1", + Acirc: "\u00C2", + Atilde: "\u00C3", + Auml: "\u00C4", + Aring: "\u00C5", + AElig: "\u00C6", + Ccedil: "\u00C7", + Egrave: "\u00C8", + Eacute: "\u00C9", + Ecirc: "\u00CA", + Euml: "\u00CB", + Igrave: "\u00CC", + Iacute: "\u00CD", + Icirc: "\u00CE", + Iuml: "\u00CF", + ETH: "\u00D0", + Ntilde: "\u00D1", + Ograve: "\u00D2", + Oacute: "\u00D3", + Ocirc: "\u00D4", + Otilde: "\u00D5", + Ouml: "\u00D6", + times: "\u00D7", + Oslash: "\u00D8", + Ugrave: "\u00D9", + Uacute: "\u00DA", + Ucirc: "\u00DB", + Uuml: "\u00DC", + Yacute: "\u00DD", + THORN: "\u00DE", + szlig: "\u00DF", + agrave: "\u00E0", + aacute: "\u00E1", + acirc: "\u00E2", + atilde: "\u00E3", + auml: "\u00E4", + aring: "\u00E5", + aelig: "\u00E6", + ccedil: "\u00E7", + egrave: "\u00E8", + eacute: "\u00E9", + ecirc: "\u00EA", + euml: "\u00EB", + igrave: "\u00EC", + iacute: "\u00ED", + icirc: "\u00EE", + iuml: "\u00EF", + eth: "\u00F0", + ntilde: "\u00F1", + ograve: "\u00F2", + oacute: "\u00F3", + ocirc: "\u00F4", + otilde: "\u00F5", + ouml: "\u00F6", + divide: "\u00F7", + oslash: "\u00F8", + ugrave: "\u00F9", + uacute: "\u00FA", + ucirc: "\u00FB", + uuml: "\u00FC", + yacute: "\u00FD", + thorn: "\u00FE", + yuml: "\u00FF", + OElig: "\u0152", + oelig: "\u0153", + Scaron: "\u0160", + scaron: "\u0161", + Yuml: "\u0178", + fnof: "\u0192", + circ: "\u02C6", + tilde: "\u02DC", + Alpha: "\u0391", + Beta: "\u0392", + Gamma: "\u0393", + Delta: "\u0394", + Epsilon: "\u0395", + Zeta: "\u0396", + Eta: "\u0397", + Theta: "\u0398", + Iota: "\u0399", + Kappa: "\u039A", + Lambda: "\u039B", + Mu: "\u039C", + Nu: "\u039D", + Xi: "\u039E", + Omicron: "\u039F", + Pi: "\u03A0", + Rho: "\u03A1", + Sigma: "\u03A3", + Tau: "\u03A4", + Upsilon: "\u03A5", + Phi: "\u03A6", + Chi: "\u03A7", + Psi: "\u03A8", + Omega: "\u03A9", + alpha: "\u03B1", + beta: "\u03B2", + gamma: "\u03B3", + delta: "\u03B4", + epsilon: "\u03B5", + zeta: "\u03B6", + eta: "\u03B7", + theta: "\u03B8", + iota: "\u03B9", + kappa: "\u03BA", + lambda: "\u03BB", + mu: "\u03BC", + nu: "\u03BD", + xi: "\u03BE", + omicron: "\u03BF", + pi: "\u03C0", + rho: "\u03C1", + sigmaf: "\u03C2", + sigma: "\u03C3", + tau: "\u03C4", + upsilon: "\u03C5", + phi: "\u03C6", + chi: "\u03C7", + psi: "\u03C8", + omega: "\u03C9", + thetasym: "\u03D1", + upsih: "\u03D2", + piv: "\u03D6", + ensp: "\u2002", + emsp: "\u2003", + thinsp: "\u2009", + zwnj: "\u200C", + zwj: "\u200D", + lrm: "\u200E", + rlm: "\u200F", + ndash: "\u2013", + mdash: "\u2014", + lsquo: "\u2018", + rsquo: "\u2019", + sbquo: "\u201A", + ldquo: "\u201C", + rdquo: "\u201D", + bdquo: "\u201E", + dagger: "\u2020", + Dagger: "\u2021", + bull: "\u2022", + hellip: "\u2026", + permil: "\u2030", + prime: "\u2032", + Prime: "\u2033", + lsaquo: "\u2039", + rsaquo: "\u203A", + oline: "\u203E", + frasl: "\u2044", + euro: "\u20AC", + image: "\u2111", + weierp: "\u2118", + real: "\u211C", + trade: "\u2122", + alefsym: "\u2135", + larr: "\u2190", + uarr: "\u2191", + rarr: "\u2192", + darr: "\u2193", + harr: "\u2194", + crarr: "\u21B5", + lArr: "\u21D0", + uArr: "\u21D1", + rArr: "\u21D2", + dArr: "\u21D3", + hArr: "\u21D4", + forall: "\u2200", + part: "\u2202", + exist: "\u2203", + empty: "\u2205", + nabla: "\u2207", + isin: "\u2208", + notin: "\u2209", + ni: "\u220B", + prod: "\u220F", + sum: "\u2211", + minus: "\u2212", + lowast: "\u2217", + radic: "\u221A", + prop: "\u221D", + infin: "\u221E", + ang: "\u2220", + and: "\u2227", + or: "\u2228", + cap: "\u2229", + cup: "\u222A", + "int": "\u222B", + there4: "\u2234", + sim: "\u223C", + cong: "\u2245", + asymp: "\u2248", + ne: "\u2260", + equiv: "\u2261", + le: "\u2264", + ge: "\u2265", + sub: "\u2282", + sup: "\u2283", + nsub: "\u2284", + sube: "\u2286", + supe: "\u2287", + oplus: "\u2295", + otimes: "\u2297", + perp: "\u22A5", + sdot: "\u22C5", + lceil: "\u2308", + rceil: "\u2309", + lfloor: "\u230A", + rfloor: "\u230B", + lang: "\u2329", + rang: "\u232A", + loz: "\u25CA", + spades: "\u2660", + clubs: "\u2663", + hearts: "\u2665", + diams: "\u2666" + }; + + function isXJSIdentifierStart(ch) { + // exclude backslash (\) + return (ch !== 92) && isIdentifierStart(ch); + } + + function isXJSIdentifierPart(ch) { + // exclude backslash (\) and add hyphen (-) + return (ch !== 92) && (ch === 45 || isIdentifierPart(ch)); + } + + function scanXJSIdentifier() { + var ch, start, id = '', namespace; + + start = index; + while (index < length) { + ch = source.charCodeAt(index); + if (!isXJSIdentifierPart(ch)) { + break; + } + id += source[index++]; + } + + if (ch === 58) { // : + ++index; + namespace = id; + id = ''; + + while (index < length) { + ch = source.charCodeAt(index); + if (!isXJSIdentifierPart(ch)) { + break; + } + id += source[index++]; + } + } + + if (!id) { + throwError({}, Messages.InvalidXJSTagName); + } + + return { + type: Token.XJSIdentifier, + value: id, + namespace: namespace, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanXJSEntity() { + var ch, str = '', count = 0, entity; + ch = source[index]; + assert(ch === '&', 'Entity must start with an ampersand'); + index++; + while (index < length && count++ < 10) { + ch = source[index++]; + if (ch === ';') { + break; + } + str += ch; + } + + if (str[0] === '#' && str[1] === 'x') { + entity = String.fromCharCode(parseInt(str.substr(2), 16)); + } else if (str[0] === '#') { + entity = String.fromCharCode(parseInt(str.substr(1), 10)); + } else { + entity = XHTMLEntities[str]; + } + return entity; + } + + function scanXJSText(stopChars) { + var ch, str = '', start; + start = index; + while (index < length) { + ch = source[index]; + if (stopChars.indexOf(ch) !== -1) { + break; + } + if (ch === '&') { + str += scanXJSEntity(); + } else { + ch = source[index++]; + if (isLineTerminator(ch.charCodeAt(0))) { + ++lineNumber; + lineStart = index; + } + str += ch; + } + } + return { + type: Token.XJSText, + value: str, + lineNumber: lineNumber, + lineStart: lineStart, + range: [start, index] + }; + } + + function scanXJSStringLiteral() { + var innerToken, quote, start; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + innerToken = scanXJSText([quote]); + + if (quote !== source[index]) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + ++index; + + innerToken.range = [start, index]; + + return innerToken; + } + + /** + * Between XJS opening and closing tags (e.g. HERE), anything that + * is not another XJS tag and is not an expression wrapped by {} is text. + */ + function advanceXJSChild() { + var ch = source.charCodeAt(index); + + // { (123) and < (60) + if (ch !== 123 && ch !== 60) { + return scanXJSText(['<', '{']); + } + + return scanPunctuator(); + } + + function parseXJSIdentifier() { + var token; + + if (lookahead.type !== Token.XJSIdentifier) { + throwUnexpected(lookahead); + } + + token = lex(); + return delegate.createXJSIdentifier(token.value, token.namespace); + } + + function parseXJSAttributeValue() { + var value; + if (match('{')) { + value = parseXJSExpressionContainer(); + if (value.expression.type === Syntax.XJSEmptyExpression) { + throwError( + value, + 'XJS attributes must only be assigned a non-empty ' + + 'expression' + ); + } + } else if (lookahead.type === Token.XJSText) { + value = delegate.createLiteral(lex()); + } else { + throwError({}, Messages.InvalidXJSAttributeValue); + } + return value; + } + + function parseXJSEmptyExpression() { + while (source.charAt(index) !== '}') { + index++; + } + return delegate.createXJSEmptyExpression(); + } + + function parseXJSExpressionContainer() { + var expression, origInXJSChild, origInXJSTag; + + origInXJSChild = state.inXJSChild; + origInXJSTag = state.inXJSTag; + state.inXJSChild = false; + state.inXJSTag = false; + + expect('{'); + + if (match('}')) { + expression = parseXJSEmptyExpression(); + } else { + expression = parseExpression(); + } + + state.inXJSChild = origInXJSChild; + state.inXJSTag = origInXJSTag; + + expect('}'); + + return delegate.createXJSExpressionContainer(expression); + } + + function parseXJSAttribute() { + var token, name, value; + + name = parseXJSIdentifier(); + + // HTML empty attribute + if (match('=')) { + lex(); + return delegate.createXJSAttribute(name, parseXJSAttributeValue()); + } + + return delegate.createXJSAttribute(name); + } + + function parseXJSChild() { + var token; + if (match('{')) { + token = parseXJSExpressionContainer(); + } else if (lookahead.type === Token.XJSText) { + token = delegate.createLiteral(lex()); + } else { + state.inXJSChild = false; + token = parseXJSElement(); + state.inXJSChild = true; + } + return token; + } + + function parseXJSClosingElement() { + var name, origInXJSTag; + origInXJSTag = state.inXJSTag; + state.inXJSTag = true; + state.inXJSChild = false; + expect('<'); + expect('/'); + name = parseXJSIdentifier(); + state.inXJSTag = origInXJSTag; + expect('>'); + return delegate.createXJSClosingElement(name); + } + + function parseXJSOpeningElement() { + var name, attribute, attributes = [], selfClosing = false, origInXJSTag; + + origInXJSTag = state.inXJSTag; + state.inXJSTag = true; + + expect('<'); + + name = parseXJSIdentifier(); + + while (index < length && + lookahead.value !== '/' && + lookahead.value !== '>') { + attributes.push(parseXJSAttribute()); + } + + state.inXJSTag = origInXJSTag; + + if (lookahead.value === '/') { + expect('/'); + expect('>'); + selfClosing = true; + } else { + state.inXJSChild = true; + expect('>'); + } + return delegate.createXJSOpeningElement(name, attributes, selfClosing); + } + + function parseXJSElement() { + var openingElement, closingElement, children = [], origInXJSChild; + + openingElement = parseXJSOpeningElement(); + + if (!openingElement.selfClosing) { + origInXJSChild = state.inXJSChild; + while (index < length) { + state.inXJSChild = false; // 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + } + + return regex; + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function LocationMarker() { + this.range = [index, index]; + this.loc = { + start: { + line: lineNumber, + column: index - lineStart + }, + end: { + line: lineNumber, + column: index - lineStart + } + }; + } + + LocationMarker.prototype = { + constructor: LocationMarker, + + end: function () { + this.range[1] = index; + this.loc.end.line = lineNumber; + this.loc.end.column = index - lineStart; + }, + + applyGroup: function (node) { + if (extra.range) { + node.groupRange = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.groupLoc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + node = delegate.postProcess(node); + } + }, + + apply: function (node) { + var nodeType = typeof node; + assert(nodeType === "object", + "Applying location marker to an unexpected node type: " + + nodeType); + + if (extra.range) { + node.range = [this.range[0], this.range[1]]; + } + if (extra.loc) { + node.loc = { + start: { + line: this.loc.start.line, + column: this.loc.start.column + }, + end: { + line: this.loc.end.line, + column: this.loc.end.column + } + }; + node = delegate.postProcess(node); + } + } + }; + + function createLocationMarker() { + return new LocationMarker(); + } + + function trackGroupExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + expect('('); + + ++state.parenthesizedCount; + + state.allowArrowFunction = !state.allowArrowFunction; + expr = parseExpression(); + state.allowArrowFunction = false; + + if (expr.type === 'ArrowFunctionExpression') { + marker.end(); + marker.apply(expr); + } else { + expect(')'); + marker.end(); + marker.applyGroup(expr); + } + + return expr; + } + + function trackLeftHandSideExpression() { + var marker, expr; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || lookahead.type === Token.Template) { + if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + marker.end(); + marker.apply(expr); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + marker.end(); + marker.apply(expr); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function trackLeftHandSideExpressionAllowCall() { + var marker, expr, args; + + skipComment(); + marker = createLocationMarker(); + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) { + if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); + marker.end(); + marker.apply(expr); + } else if (match('[')) { + expr = delegate.createMemberExpression('[', expr, parseComputedMember()); + marker.end(); + marker.apply(expr); + } else if (match('.')) { + expr = delegate.createMemberExpression('.', expr, parseNonComputedMember()); + marker.end(); + marker.apply(expr); + } else { + expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()); + marker.end(); + marker.apply(expr); + } + } + + return expr; + } + + function filterGroup(node) { + var n, i, entry; + + n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {}; + for (i in node) { + if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') { + entry = node[i]; + if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) { + n[i] = entry; + } else { + n[i] = filterGroup(entry); + } + } + } + return n; + } + + function wrapTrackingFunction(range, loc, preserveWhitespace) { + + return function (parseFunction) { + + function isBinary(node) { + return node.type === Syntax.LogicalExpression || + node.type === Syntax.BinaryExpression; + } + + function visit(node) { + var start, end; + + if (isBinary(node.left)) { + visit(node.left); + } + if (isBinary(node.right)) { + visit(node.right); + } + + if (range) { + if (node.left.groupRange || node.right.groupRange) { + start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0]; + end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1]; + node.range = [start, end]; + } else if (typeof node.range === 'undefined') { + start = node.left.range[0]; + end = node.right.range[1]; + node.range = [start, end]; + } + } + if (loc) { + if (node.left.groupLoc || node.right.groupLoc) { + start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start; + end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end; + node.loc = { + start: start, + end: end + }; + node = delegate.postProcess(node); + } else if (typeof node.loc === 'undefined') { + node.loc = { + start: node.left.loc.start, + end: node.right.loc.end + }; + node = delegate.postProcess(node); + } + } + } + + return function () { + var marker, node; + + if (!preserveWhitespace) { + skipComment(); + } + + marker = createLocationMarker(); + node = parseFunction.apply(null, arguments); + marker.end(); + + if (range && typeof node.range === 'undefined') { + marker.apply(node); + } + + if (loc && typeof node.loc === 'undefined') { + marker.apply(node); + } + + if (isBinary(node)) { + visit(node); + } + + return node; + }; + }; + } + + function patch() { + + var wrapTracking, wrapTrackingPreserveWhitespace; + + if (extra.comments) { + extra.skipComment = skipComment; + skipComment = scanComment; + } + + if (extra.range || extra.loc) { + + extra.parseGroupExpression = parseGroupExpression; + extra.parseLeftHandSideExpression = parseLeftHandSideExpression; + extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall; + parseGroupExpression = trackGroupExpression; + parseLeftHandSideExpression = trackLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall; + + wrapTracking = wrapTrackingFunction(extra.range, extra.loc); + wrapTrackingPreserveWhitespace = + wrapTrackingFunction(extra.range, extra.loc, true); + + extra.parseAssignmentExpression = parseAssignmentExpression; + extra.parseBinaryExpression = parseBinaryExpression; + extra.parseBlock = parseBlock; + extra.parseFunctionSourceElements = parseFunctionSourceElements; + extra.parseCatchClause = parseCatchClause; + extra.parseComputedMember = parseComputedMember; + extra.parseConditionalExpression = parseConditionalExpression; + extra.parseConstLetDeclaration = parseConstLetDeclaration; + extra.parseExportBatchSpecifier = parseExportBatchSpecifier; + extra.parseExportDeclaration = parseExportDeclaration; + extra.parseExportSpecifier = parseExportSpecifier; + extra.parseExpression = parseExpression; + extra.parseForVariableDeclaration = parseForVariableDeclaration; + extra.parseFunctionDeclaration = parseFunctionDeclaration; + extra.parseFunctionExpression = parseFunctionExpression; + extra.parseParams = parseParams; + extra.parseImportDeclaration = parseImportDeclaration; + extra.parseImportSpecifier = parseImportSpecifier; + extra.parseModuleDeclaration = parseModuleDeclaration; + extra.parseModuleBlock = parseModuleBlock; + extra.parseNewExpression = parseNewExpression; + extra.parseNonComputedProperty = parseNonComputedProperty; + extra.parseObjectProperty = parseObjectProperty; + extra.parseObjectPropertyKey = parseObjectPropertyKey; + extra.parsePostfixExpression = parsePostfixExpression; + extra.parsePrimaryExpression = parsePrimaryExpression; + extra.parseProgram = parseProgram; + extra.parsePropertyFunction = parsePropertyFunction; + extra.parseSpreadOrAssignmentExpression = parseSpreadOrAssignmentExpression; + extra.parseTemplateElement = parseTemplateElement; + extra.parseTemplateLiteral = parseTemplateLiteral; + extra.parseTypeAnnotatableIdentifier = parseTypeAnnotatableIdentifier; + extra.parseTypeAnnotation = parseTypeAnnotation; + extra.parseStatement = parseStatement; + extra.parseSwitchCase = parseSwitchCase; + extra.parseUnaryExpression = parseUnaryExpression; + extra.parseVariableDeclaration = parseVariableDeclaration; + extra.parseVariableIdentifier = parseVariableIdentifier; + extra.parseMethodDefinition = parseMethodDefinition; + extra.parseClassDeclaration = parseClassDeclaration; + extra.parseClassExpression = parseClassExpression; + extra.parseClassBody = parseClassBody; + extra.parseXJSIdentifier = parseXJSIdentifier; + extra.parseXJSChild = parseXJSChild; + extra.parseXJSAttribute = parseXJSAttribute; + extra.parseXJSAttributeValue = parseXJSAttributeValue; + extra.parseXJSExpressionContainer = parseXJSExpressionContainer; + extra.parseXJSEmptyExpression = parseXJSEmptyExpression; + extra.parseXJSElement = parseXJSElement; + extra.parseXJSClosingElement = parseXJSClosingElement; + extra.parseXJSOpeningElement = parseXJSOpeningElement; + + parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression); + parseBinaryExpression = wrapTracking(extra.parseBinaryExpression); + parseBlock = wrapTracking(extra.parseBlock); + parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements); + parseCatchClause = wrapTracking(extra.parseCatchClause); + parseComputedMember = wrapTracking(extra.parseComputedMember); + parseConditionalExpression = wrapTracking(extra.parseConditionalExpression); + parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration); + parseExportBatchSpecifier = wrapTracking(parseExportBatchSpecifier); + parseExportDeclaration = wrapTracking(parseExportDeclaration); + parseExportSpecifier = wrapTracking(parseExportSpecifier); + parseExpression = wrapTracking(extra.parseExpression); + parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration); + parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration); + parseFunctionExpression = wrapTracking(extra.parseFunctionExpression); + parseParams = wrapTracking(extra.parseParams); + parseImportDeclaration = wrapTracking(extra.parseImportDeclaration); + parseImportSpecifier = wrapTracking(extra.parseImportSpecifier); + parseModuleDeclaration = wrapTracking(extra.parseModuleDeclaration); + parseModuleBlock = wrapTracking(extra.parseModuleBlock); + parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression); + parseNewExpression = wrapTracking(extra.parseNewExpression); + parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty); + parseObjectProperty = wrapTracking(extra.parseObjectProperty); + parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey); + parsePostfixExpression = wrapTracking(extra.parsePostfixExpression); + parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression); + parseProgram = wrapTracking(extra.parseProgram); + parsePropertyFunction = wrapTracking(extra.parsePropertyFunction); + parseTemplateElement = wrapTracking(extra.parseTemplateElement); + parseTemplateLiteral = wrapTracking(extra.parseTemplateLiteral); + parseTypeAnnotatableIdentifier = wrapTracking(extra.parseTypeAnnotatableIdentifier); + parseTypeAnnotation = wrapTracking(extra.parseTypeAnnotation); + parseSpreadOrAssignmentExpression = wrapTracking(extra.parseSpreadOrAssignmentExpression); + parseStatement = wrapTracking(extra.parseStatement); + parseSwitchCase = wrapTracking(extra.parseSwitchCase); + parseUnaryExpression = wrapTracking(extra.parseUnaryExpression); + parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration); + parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier); + parseMethodDefinition = wrapTracking(extra.parseMethodDefinition); + parseClassDeclaration = wrapTracking(extra.parseClassDeclaration); + parseClassExpression = wrapTracking(extra.parseClassExpression); + parseClassBody = wrapTracking(extra.parseClassBody); + parseXJSIdentifier = wrapTracking(extra.parseXJSIdentifier); + parseXJSChild = wrapTrackingPreserveWhitespace(extra.parseXJSChild); + parseXJSAttribute = wrapTracking(extra.parseXJSAttribute); + parseXJSAttributeValue = wrapTracking(extra.parseXJSAttributeValue); + parseXJSExpressionContainer = wrapTracking(extra.parseXJSExpressionContainer); + parseXJSEmptyExpression = wrapTrackingPreserveWhitespace(extra.parseXJSEmptyExpression); + parseXJSElement = wrapTracking(extra.parseXJSElement); + parseXJSClosingElement = wrapTracking(extra.parseXJSClosingElement); + parseXJSOpeningElement = wrapTracking(extra.parseXJSOpeningElement); + } + + if (typeof extra.tokens !== 'undefined') { + extra.advance = advance; + extra.scanRegExp = scanRegExp; + + advance = collectToken; + scanRegExp = collectRegex; + } + } + + function unpatch() { + if (typeof extra.skipComment === 'function') { + skipComment = extra.skipComment; + } + + if (extra.range || extra.loc) { + parseAssignmentExpression = extra.parseAssignmentExpression; + parseBinaryExpression = extra.parseBinaryExpression; + parseBlock = extra.parseBlock; + parseFunctionSourceElements = extra.parseFunctionSourceElements; + parseCatchClause = extra.parseCatchClause; + parseComputedMember = extra.parseComputedMember; + parseConditionalExpression = extra.parseConditionalExpression; + parseConstLetDeclaration = extra.parseConstLetDeclaration; + parseExportBatchSpecifier = extra.parseExportBatchSpecifier; + parseExportDeclaration = extra.parseExportDeclaration; + parseExportSpecifier = extra.parseExportSpecifier; + parseExpression = extra.parseExpression; + parseForVariableDeclaration = extra.parseForVariableDeclaration; + parseFunctionDeclaration = extra.parseFunctionDeclaration; + parseFunctionExpression = extra.parseFunctionExpression; + parseImportDeclaration = extra.parseImportDeclaration; + parseImportSpecifier = extra.parseImportSpecifier; + parseGroupExpression = extra.parseGroupExpression; + parseLeftHandSideExpression = extra.parseLeftHandSideExpression; + parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall; + parseModuleDeclaration = extra.parseModuleDeclaration; + parseModuleBlock = extra.parseModuleBlock; + parseNewExpression = extra.parseNewExpression; + parseNonComputedProperty = extra.parseNonComputedProperty; + parseObjectProperty = extra.parseObjectProperty; + parseObjectPropertyKey = extra.parseObjectPropertyKey; + parsePostfixExpression = extra.parsePostfixExpression; + parsePrimaryExpression = extra.parsePrimaryExpression; + parseProgram = extra.parseProgram; + parsePropertyFunction = extra.parsePropertyFunction; + parseTemplateElement = extra.parseTemplateElement; + parseTemplateLiteral = extra.parseTemplateLiteral; + parseTypeAnnotatableIdentifier = extra.parseTypeAnnotatableIdentifier; + parseTypeAnnotation = extra.parseTypeAnnotation; + parseSpreadOrAssignmentExpression = extra.parseSpreadOrAssignmentExpression; + parseStatement = extra.parseStatement; + parseSwitchCase = extra.parseSwitchCase; + parseUnaryExpression = extra.parseUnaryExpression; + parseVariableDeclaration = extra.parseVariableDeclaration; + parseVariableIdentifier = extra.parseVariableIdentifier; + parseMethodDefinition = extra.parseMethodDefinition; + parseClassDeclaration = extra.parseClassDeclaration; + parseClassExpression = extra.parseClassExpression; + parseClassBody = extra.parseClassBody; + parseXJSIdentifier = extra.parseXJSIdentifier; + parseXJSChild = extra.parseXJSChild; + parseXJSAttribute = extra.parseXJSAttribute; + parseXJSAttributeValue = extra.parseXJSAttributeValue; + parseXJSExpressionContainer = extra.parseXJSExpressionContainer; + parseXJSEmptyExpression = extra.parseXJSEmptyExpression; + parseXJSElement = extra.parseXJSElement; + parseXJSClosingElement = extra.parseXJSClosingElement; + parseXJSOpeningElement = extra.parseXJSOpeningElement; + } + + if (typeof extra.scanRegExp === 'function') { + advance = extra.advance; + scanRegExp = extra.scanRegExp; + } + } + + // This is used to modify the delegate. + + function extend(object, properties) { + var entry, result = {}; + + for (entry in object) { + if (object.hasOwnProperty(entry)) { + result[entry] = object[entry]; + } + } + + for (entry in properties) { + if (properties.hasOwnProperty(entry)) { + result[entry] = properties[entry]; + } + } + + return result; + } + + function tokenize(code, options) { + var toString, + token, + tokens; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowKeyword: true, + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false + }; + + extra = {}; + + // Options matching. + options = options || {}; + + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenize = true; + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; + + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + } + } + + patch(); + + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; + } + + token = lex(); + while (lookahead.type !== Token.EOF) { + try { + token = lex(); + } catch (lexError) { + token = lookahead; + if (extra.errors) { + extra.errors.push(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; + } + } + } + + filterTokenLocation(); + tokens = extra.tokens; + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + tokens.comments = extra.comments; + } + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + return tokens; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowKeyword: false, + allowIn: true, + labelSet: {}, + parenthesizedCount: 0, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + yieldAllowed: false, + yieldFound: false + }; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (extra.loc && options.source !== null && options.source !== undefined) { + delegate = extend(delegate, { + 'postProcess': function (node) { + node.loc.source = toString(options.source); + return node; + } + }); + } + + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + } + + if (length > 0) { + if (typeof source[0] === 'undefined') { + // Try first to convert to a string. This is good as fast path + // for old IE which understands string indexing for string + // literals only and not for string object. + if (code instanceof String) { + source = code.valueOf(); + } + } + } + + patch(); + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + filterCommentLocation(); + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + if (extra.range || extra.loc) { + program.body = filterGroup(program.body); + } + } catch (e) { + throw e; + } finally { + unpatch(); + extra = {}; + } + + return program; + } + + // Sync with package.json and component.json. + exports.version = '1.1.0-dev-harmony'; + + exports.tokenize = tokenize; + + exports.parse = parse; + + // Deep copy. + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ + +},{}],6:[function(require,module,exports){ +var Base62 = (function (my) { + my.chars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] + + my.encode = function(i){ + if (i === 0) {return '0'} + var s = '' + while (i > 0) { + s = this.chars[i % 62] + s + i = Math.floor(i/62) + } + return s + }; + my.decode = function(a,b,c,d){ + for ( + b = c = ( + a === (/\W|_|^$/.test(a += "") || a) + ) - 1; + d = a.charCodeAt(c++); + ) + b = b * 62 + d - [, 48, 29, 87][d >> 5]; + return b + }; + + return my; +}({})); + +module.exports = Base62 +},{}],7:[function(require,module,exports){ +/* + * Copyright 2009-2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.txt or: + * http://opensource.org/licenses/BSD-3-Clause + */ +exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator; +exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer; +exports.SourceNode = require('./source-map/source-node').SourceNode; + +},{"./source-map/source-map-consumer":12,"./source-map/source-map-generator":13,"./source-map/source-node":14}],8:[function(require,module,exports){ +/* -*- 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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(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; + }; + + /** + * Because behavior goes wacky when you set `__proto__` on `this._set`, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + ArraySet.prototype._toSetString = function ArraySet__toSetString (aStr) { + return "$" + aStr; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + 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[this._toSetString(aStr)] = idx; + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + this._toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[this._toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + 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; + +}); + +},{"amdefine":16}],9:[function(require,module,exports){ +/* -*- 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 + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(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) + }; + }; + +}); + +},{"./base64":10,"amdefine":16}],10:[function(require,module,exports){ +/* -*- 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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(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); + }; + +}); + +},{"amdefine":16}],11:[function(require,module,exports){ +/* -*- 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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(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; + }; + +}); + +},{"amdefine":16}],12:[function(require,module,exports){ +/* -*- 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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(function (require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * 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. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + 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._sourceRoot = sourceRoot; + this.file = file; + + // `this._generatedMappings` and `this._originalMappings` hold the parsed + // mapping coordinates from the source map's "mappings" attribute. Each + // object in the array is of the form + // + // { + // generatedLine: The line number in the generated code, + // generatedColumn: The column number in the generated code, + // source: The path to the original source file that generated this + // chunk of code, + // originalLine: The line number in the original source that + // corresponds to this chunk of generated code, + // originalColumn: The column number in the original source that + // corresponds to this chunk of generated code, + // name: The name of the original symbol which generated this chunk of + // code. + // } + // + // All properties except for `generatedLine` and `generatedColumn` can be + // `null`. + // + // `this._generatedMappings` is ordered by the generated positions. + // + // `this._originalMappings` is ordered by the original positions. + this._generatedMappings = []; + this._originalMappings = []; + this._parseMappings(mappings, sourceRoot); + } + + /** + * The version of the source mapping spec that we are consuming. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this._sourceRoot ? util.join(this._sourceRoot, s) : s; + }, this); + } + }); + + /** + * 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); + this._originalMappings.push(mapping); + } + } + + this._originalMappings.sort(this._compareOriginalPositions); + }; + + /** + * Comparator between two mappings where the original positions are compared. + */ + SourceMapConsumer.prototype._compareOriginalPositions = + function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) { + if (mappingA.source > mappingB.source) { + return 1; + } + else if (mappingA.source < mappingB.source) { + return -1; + } + else { + var cmp = mappingA.originalLine - mappingB.originalLine; + return cmp === 0 + ? mappingA.originalColumn - mappingB.originalColumn + : cmp; + } + }; + + /** + * Comparator between two mappings where the generated positions are compared. + */ + SourceMapConsumer.prototype._compareGeneratedPositions = + function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) { + var cmp = mappingA.generatedLine - mappingB.generatedLine; + return cmp === 0 + ? mappingA.generatedColumn - mappingB.generatedColumn + : cmp; + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * 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) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + this._compareGeneratedPositions) + + 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 + }; + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + this._compareOriginalPositions) + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. This function should + * not mutate the mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + mappings.forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); + +},{"./array-set":8,"./base64-vlq":9,"./binary-search":11,"./util":15,"amdefine":16}],13:[function(require,module,exports){ +/* -*- 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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(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; + }; + + /** + * Externalize the source map. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + 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 map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); + +},{"./array-set":8,"./base64-vlq":9,"./util":15,"amdefine":16}],14:[function(require,module,exports){ +/* -*- 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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(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") { + 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 instanceof SourceNode || 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) { + 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.length - 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; + +}); + +},{"./source-map-generator":13,"amdefine":16}],15:[function(require,module,exports){ +/* -*- 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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module); +} +define(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; + +}); + +},{"amdefine":16}],16:[function(require,module,exports){ +var process=require("__browserify_process"),__filename="/../node_modules/jstransform/node_modules/source-map/node_modules/amdefine/amdefine.js";/** vim: et:ts=4:sw=4:sts=4 + * @license amdefine 0.1.0 Copyright (c) 2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/amdefine for details + */ + +/*jslint node: true */ +/*global module, process */ +'use strict'; + +/** + * Creates a define for node. + * @param {Object} module the "module" object that is defined by Node for the + * current module. + * @param {Function} [requireFn]. Node's require function for the current module. + * It only needs to be passed in Node versions before 0.5, when module.require + * did not exist. + * @returns {Function} a define function that is usable for the current node + * module. + */ +function amdefine(module, requireFn) { + 'use strict'; + var defineCache = {}, + loaderCache = {}, + alreadyCalled = false, + path = require('path'), + makeRequire, stringRequire; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i+= 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + function normalize(name, baseName) { + var baseParts; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + baseParts = baseName.split('/'); + baseParts = baseParts.slice(0, baseParts.length - 1); + baseParts = baseParts.concat(name.split('/')); + trimDots(baseParts); + name = baseParts.join('/'); + } + } + + return name; + } + + /** + * Create the normalize() function passed to a loader plugin's + * normalize method. + */ + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(id) { + function load(value) { + loaderCache[id] = value; + } + + load.fromText = function (id, text) { + //This one is difficult because the text can/probably uses + //define, and any relative paths and requires should be relative + //to that id was it would be found on disk. But this would require + //bootstrapping a module/require fairly deeply from node core. + //Not sure how best to go about that yet. + throw new Error('amdefine does not implement load.fromText'); + }; + + return load; + } + + makeRequire = function (systemRequire, exports, module, relId) { + function amdRequire(deps, callback) { + if (typeof deps === 'string') { + //Synchronous, single module require('') + return stringRequire(systemRequire, exports, module, deps, relId); + } else { + //Array of dependencies with a callback. + + //Convert the dependencies to modules. + deps = deps.map(function (depName) { + return stringRequire(systemRequire, exports, module, depName, relId); + }); + + //Wait for next tick to call back the require call. + process.nextTick(function () { + callback.apply(null, deps); + }); + } + } + + amdRequire.toUrl = function (filePath) { + if (filePath.indexOf('.') === 0) { + return normalize(filePath, path.dirname(module.filename)); + } else { + return filePath; + } + }; + + return amdRequire; + }; + + //Favor explicit value, passed in if the module wants to support Node 0.4. + requireFn = requireFn || function req() { + return module.require.apply(module, arguments); + }; + + function runFactory(id, deps, factory) { + var r, e, m, result; + + if (id) { + e = loaderCache[id] = {}; + m = { + id: id, + uri: __filename, + exports: e + }; + r = makeRequire(requireFn, e, m, id); + } else { + //Only support one define call per file + if (alreadyCalled) { + throw new Error('amdefine with no module ID cannot be called more than once per file.'); + } + alreadyCalled = true; + + //Use the real variables from node + //Use module.exports for exports, since + //the exports in here is amdefine exports. + e = module.exports; + m = module; + r = makeRequire(requireFn, e, m, module.id); + } + + //If there are dependencies, they are strings, so need + //to convert them to dependency values. + if (deps) { + deps = deps.map(function (depName) { + return r(depName); + }); + } + + //Call the factory with the right dependencies. + if (typeof factory === 'function') { + result = factory.apply(m.exports, deps); + } else { + result = factory; + } + + if (result !== undefined) { + m.exports = result; + if (id) { + loaderCache[id] = m.exports; + } + } + } + + stringRequire = function (systemRequire, exports, module, id, relId) { + //Split the ID by a ! so that + var index = id.indexOf('!'), + originalId = id, + prefix, plugin; + + if (index === -1) { + id = normalize(id, relId); + + //Straight module lookup. If it is one of the special dependencies, + //deal with it, otherwise, delegate to node. + if (id === 'require') { + return makeRequire(systemRequire, exports, module, relId); + } else if (id === 'exports') { + return exports; + } else if (id === 'module') { + return module; + } else if (loaderCache.hasOwnProperty(id)) { + return loaderCache[id]; + } else if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } else { + if(systemRequire) { + return systemRequire(originalId); + } else { + throw new Error('No module with ID: ' + id); + } + } + } else { + //There is a plugin in play. + prefix = id.substring(0, index); + id = id.substring(index + 1, id.length); + + plugin = stringRequire(systemRequire, exports, module, prefix, relId); + + if (plugin.normalize) { + id = plugin.normalize(id, makeNormalize(relId)); + } else { + //Normalize the ID normally. + id = normalize(id, relId); + } + + if (loaderCache[id]) { + return loaderCache[id]; + } else { + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); + + return loaderCache[id]; + } + } + }; + + //Create a define function specific to the module asking for amdefine. + function define(id, deps, factory) { + if (Array.isArray(id)) { + factory = deps; + deps = id; + id = undefined; + } else if (typeof id !== 'string') { + factory = id; + id = deps = undefined; + } + + if (deps && !Array.isArray(deps)) { + factory = deps; + deps = undefined; + } + + if (!deps) { + deps = ['require', 'exports', 'module']; + } + + //Set up properties for this module. If an ID, then use + //internal cache. If no ID, then use the external variables + //for this node module. + if (id) { + //Put the module in deep freeze until there is a + //require call for it. + defineCache[id] = [id, deps, factory]; + } else { + runFactory(id, deps, factory); + } + } + + //define.require, which has access to all the values in the + //cache. Useful for AMD modules that all have IDs in the file, + //but need to finally export a value to node based on one of those + //IDs. + define.require = function (id) { + if (loaderCache[id]) { + return loaderCache[id]; + } + + if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } + }; + + define.amd = {}; + + return define; +} + +module.exports = amdefine; + +},{"__browserify_process":4,"path":2}],17:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var docblockRe = /^\s*(\/\*\*(.|\r?\n)*?\*\/)/; +var ltrimRe = /^\s*/; +/** + * @param {String} contents + * @return {String} + */ +function extract(contents) { + var match = contents.match(docblockRe); + if (match) { + return match[0].replace(ltrimRe, '') || ''; + } + return ''; +} + + +var commentStartRe = /^\/\*\*?/; +var commentEndRe = /\*\/$/; +var wsRe = /[\t ]+/g; +var stringStartRe = /(\r?\n|^) *\*/g; +var multilineRe = /(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *([^@\r\n\s][^@\r\n]+?) *\r?\n/g; +var propertyRe = /(?:^|\r?\n) *@(\S+) *([^\r\n]*)/g; + +/** + * @param {String} contents + * @return {Array} + */ +function parse(docblock) { + docblock = docblock + .replace(commentStartRe, '') + .replace(commentEndRe, '') + .replace(wsRe, ' ') + .replace(stringStartRe, '$1'); + + // Normalize multi-line directives + var prev = ''; + while (prev != docblock) { + prev = docblock; + docblock = docblock.replace(multilineRe, "\n$1 $2\n"); + } + docblock = docblock.trim(); + + var result = []; + var match; + while (match = propertyRe.exec(docblock)) { + result.push([match[1], match[2]]); + } + + return result; +} + +/** + * Same as parse but returns an object of prop: value instead of array of paris + * If a property appers more than once the last one will be returned + * + * @param {String} contents + * @return {Object} + */ +function parseAsObject(docblock) { + var pairs = parse(docblock); + var result = {}; + for (var i = 0; i < pairs.length; i++) { + result[pairs[i][0]] = pairs[i][1]; + } + return result; +} + + +exports.extract = extract; +exports.parse = parse; +exports.parseAsObject = parseAsObject; + +},{}],18:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/*jslint node: true*/ +"use strict"; + +/** + * Syntax transfomer for javascript. Takes the source in, spits the source + * out. + * + * Parses input source with esprima, applies the given list of visitors to the + * AST tree, and returns the resulting output. + */ +var esprima = require('esprima-fb'); + +var createState = require('./utils').createState; +var catchup = require('./utils').catchup; +var updateState = require('./utils').updateState; +var analyzeAndTraverse = require('./utils').analyzeAndTraverse; + +var Syntax = esprima.Syntax; + +/** + * @param {object} node + * @param {object} parentNode + * @return {boolean} + */ +function _nodeIsClosureScopeBoundary(node, parentNode) { + if (node.type === Syntax.Program) { + return true; + } + + var parentIsFunction = + parentNode.type === Syntax.FunctionDeclaration + || parentNode.type === Syntax.FunctionExpression; + + return node.type === Syntax.BlockStatement && parentIsFunction; +} + +function _nodeIsBlockScopeBoundary(node, parentNode) { + if (node.type === Syntax.Program) { + return false; + } + + return node.type === Syntax.BlockStatement + && parentNode.type === Syntax.CatchClause; +} + +/** + * @param {object} node + * @param {function} visitor + * @param {array} path + * @param {object} state + */ +function traverse(node, path, state) { + // Create a scope stack entry if this is the first node we've encountered in + // its local scope + var parentNode = path[0]; + if (!Array.isArray(node) && state.localScope.parentNode !== parentNode) { + if (_nodeIsClosureScopeBoundary(node, parentNode)) { + var scopeIsStrict = + state.scopeIsStrict + || node.body.length > 0 + && node.body[0].type === Syntax.ExpressionStatement + && node.body[0].expression.type === Syntax.Literal + && node.body[0].expression.value === 'use strict'; + + if (node.type === Syntax.Program) { + state = updateState(state, { + scopeIsStrict: scopeIsStrict + }); + } else { + state = updateState(state, { + localScope: { + parentNode: parentNode, + parentScope: state.localScope, + identifiers: {} + }, + scopeIsStrict: scopeIsStrict + }); + + // All functions have an implicit 'arguments' object in scope + state.localScope.identifiers['arguments'] = true; + + // Include function arg identifiers in the scope boundaries of the + // function + if (parentNode.params.length > 0) { + var param; + for (var i = 0; i < parentNode.params.length; i++) { + param = parentNode.params[i]; + if (param.type === Syntax.Identifier) { + state.localScope.identifiers[param.name] = true; + } + } + } + + // Named FunctionExpressions scope their name within the body block of + // themselves only + if (parentNode.type === Syntax.FunctionExpression && parentNode.id) { + state.localScope.identifiers[parentNode.id.name] = true; + } + } + + // Traverse and find all local identifiers in this closure first to + // account for function/variable declaration hoisting + collectClosureIdentsAndTraverse(node, path, state); + } + + if (_nodeIsBlockScopeBoundary(node, parentNode)) { + state = updateState(state, { + localScope: { + parentNode: parentNode, + parentScope: state.localScope, + identifiers: {} + } + }); + + if (parentNode.type === Syntax.CatchClause) { + state.localScope.identifiers[parentNode.param.name] = true; + } + collectBlockIdentsAndTraverse(node, path, state); + } + } + + // Only catchup() before and after traversing a child node + function traverser(node, path, state) { + node.range && catchup(node.range[0], state); + traverse(node, path, state); + node.range && catchup(node.range[1], state); + } + + analyzeAndTraverse(walker, traverser, node, path, state); +} + +function collectClosureIdentsAndTraverse(node, path, state) { + analyzeAndTraverse( + visitLocalClosureIdentifiers, + collectClosureIdentsAndTraverse, + node, + path, + state + ); +} + +function collectBlockIdentsAndTraverse(node, path, state) { + analyzeAndTraverse( + visitLocalBlockIdentifiers, + collectBlockIdentsAndTraverse, + node, + path, + state + ); +} + +function visitLocalClosureIdentifiers(node, path, state) { + var identifiers = state.localScope.identifiers; + switch (node.type) { + case Syntax.FunctionExpression: + // Function expressions don't get their names (if there is one) added to + // the closure scope they're defined in + return false; + case Syntax.ClassDeclaration: + case Syntax.ClassExpression: + case Syntax.FunctionDeclaration: + if (node.id) { + identifiers[node.id.name] = true; + } + return false; + case Syntax.VariableDeclarator: + if (path[0].kind === 'var') { + identifiers[node.id.name] = true; + } + break; + } +} + +function visitLocalBlockIdentifiers(node, path, state) { + // TODO: Support 'let' here...maybe...one day...or something... + if (node.type === Syntax.CatchClause) { + return false; + } +} + +function walker(node, path, state) { + var visitors = state.g.visitors; + for (var i = 0; i < visitors.length; i++) { + if (visitors[i].test(node, path, state)) { + return visitors[i](traverse, node, path, state); + } + } +} + +/** + * Applies all available transformations to the source + * @param {array} visitors + * @param {string} source + * @param {?object} options + * @return {object} + */ +function transform(visitors, source, options) { + options = options || {}; + + var ast; + try { + ast = esprima.parse(source, { + comment: true, + loc: true, + range: true + }); + } catch (e) { + e.message = 'Parse Error: ' + e.message; + throw e; + } + var state = createState(source, ast, options); + state.g.visitors = visitors; + + if (options.sourceMap) { + var SourceMapGenerator = require('source-map').SourceMapGenerator; + state.g.sourceMap = new SourceMapGenerator({file: 'transformed.js'}); + } + + traverse(ast, [], state); + catchup(source.length, state); + + var ret = {code: state.g.buffer}; + if (options.sourceMap) { + ret.sourceMap = state.g.sourceMap; + ret.sourceMapFilename = options.filename || 'source.js'; + } + return ret; +} + +exports.transform = transform; + +},{"./utils":19,"esprima-fb":5,"source-map":7}],19:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/*jslint node: true*/ + +/** + * A `state` object represents the state of the parser. It has "local" and + * "global" parts. Global contains parser position, source, etc. Local contains + * scope based properties like current class name. State should contain all the + * info required for transformation. It's the only mandatory object that is + * being passed to every function in transform chain. + * + * @param {string} source + * @param {object} transformOptions + * @return {object} + */ +function createState(source, rootNode, transformOptions) { + return { + /** + * A tree representing the current local scope (and its lexical scope chain) + * Useful for tracking identifiers from parent scopes, etc. + * @type {Object} + */ + localScope: { + parentNode: rootNode, + parentScope: null, + identifiers: {} + }, + /** + * The name (and, if applicable, expression) of the super class + * @type {Object} + */ + superClass: null, + /** + * The namespace to use when munging identifiers + * @type {String} + */ + mungeNamespace: '', + /** + * Ref to the node for the FunctionExpression of the enclosing + * MethodDefinition + * @type {Object} + */ + methodFuncNode: null, + /** + * Name of the enclosing class + * @type {String} + */ + className: null, + /** + * Whether we're currently within a `strict` scope + * @type {Bool} + */ + scopeIsStrict: null, + /** + * Global state (not affected by updateState) + * @type {Object} + */ + g: { + /** + * A set of general options that transformations can consider while doing + * a transformation: + * + * - minify + * Specifies that transformation steps should do their best to minify + * the output source when possible. This is useful for places where + * minification optimizations are possible with higher-level context + * info than what jsxmin can provide. + * + * For example, the ES6 class transform will minify munged private + * variables if this flag is set. + */ + opts: transformOptions, + /** + * Current position in the source code + * @type {Number} + */ + position: 0, + /** + * Buffer containing the result + * @type {String} + */ + buffer: '', + /** + * Indentation offset (only negative offset is supported now) + * @type {Number} + */ + indentBy: 0, + /** + * Source that is being transformed + * @type {String} + */ + source: source, + + /** + * Cached parsed docblock (see getDocblock) + * @type {object} + */ + docblock: null, + + /** + * Whether the thing was used + * @type {Boolean} + */ + tagNamespaceUsed: false, + + /** + * If using bolt xjs transformation + * @type {Boolean} + */ + isBolt: undefined, + + /** + * Whether to record source map (expensive) or not + * @type {SourceMapGenerator|null} + */ + sourceMap: null, + + /** + * Filename of the file being processed. Will be returned as a source + * attribute in the source map + */ + sourceMapFilename: 'source.js', + + /** + * Only when source map is used: last line in the source for which + * source map was generated + * @type {Number} + */ + sourceLine: 1, + + /** + * Only when source map is used: last line in the buffer for which + * source map was generated + * @type {Number} + */ + bufferLine: 1, + + /** + * The top-level Program AST for the original file. + */ + originalProgramAST: null, + + sourceColumn: 0, + bufferColumn: 0 + } + }; +} + +/** + * Updates a copy of a given state with "update" and returns an updated state. + * + * @param {object} state + * @param {object} update + * @return {object} + */ +function updateState(state, update) { + var ret = Object.create(state); + Object.keys(update).forEach(function(updatedKey) { + ret[updatedKey] = update[updatedKey]; + }); + return ret; +} + +/** + * Given a state fill the resulting buffer from the original source up to + * the end + * + * @param {number} end + * @param {object} state + * @param {?function} contentTransformer Optional callback to transform newly + * added content. + */ +function catchup(end, state, contentTransformer) { + if (end < state.g.position) { + // cannot move backwards + return; + } + var source = state.g.source.substring(state.g.position, end); + var transformed = updateIndent(source, state); + if (state.g.sourceMap && transformed) { + // record where we are + state.g.sourceMap.addMapping({ + generated: { line: state.g.bufferLine, column: state.g.bufferColumn }, + original: { line: state.g.sourceLine, column: state.g.sourceColumn }, + source: state.g.sourceMapFilename + }); + + // record line breaks in transformed source + var sourceLines = source.split('\n'); + var transformedLines = transformed.split('\n'); + // Add line break mappings between last known mapping and the end of the + // added piece. So for the code piece + // (foo, bar); + // > var x = 2; + // > var b = 3; + // var c = + // only add lines marked with ">": 2, 3. + for (var i = 1; i < sourceLines.length - 1; i++) { + state.g.sourceMap.addMapping({ + generated: { line: state.g.bufferLine, column: 0 }, + original: { line: state.g.sourceLine, column: 0 }, + source: state.g.sourceMapFilename + }); + state.g.sourceLine++; + state.g.bufferLine++; + } + // offset for the last piece + if (sourceLines.length > 1) { + state.g.sourceLine++; + state.g.bufferLine++; + state.g.sourceColumn = 0; + state.g.bufferColumn = 0; + } + state.g.sourceColumn += sourceLines[sourceLines.length - 1].length; + state.g.bufferColumn += + transformedLines[transformedLines.length - 1].length; + } + state.g.buffer += + contentTransformer ? contentTransformer(transformed) : transformed; + state.g.position = end; +} + +/** + * Removes all non-whitespace characters + */ +var reNonWhite = /(\S)/g; +function stripNonWhite(value) { + return value.replace(reNonWhite, function() { + return ''; + }); +} + +/** + * Catches up as `catchup` but removes all non-whitespace characters. + */ +function catchupWhiteSpace(end, state) { + catchup(end, state, stripNonWhite); +} + +/** + * Removes all non-newline characters + */ +var reNonNewline = /[^\n]/g; +function stripNonNewline(value) { + return value.replace(reNonNewline, function() { + return ''; + }); +} + +/** + * Catches up as `catchup` but removes all non-newline characters. + * + * Equivalent to appending as many newlines as there are in the original source + * between the current position and `end`. + */ +function catchupNewlines(end, state) { + catchup(end, state, stripNonNewline); +} + + +/** + * Same as catchup but does not touch the buffer + * + * @param {number} end + * @param {object} state + */ +function move(end, state) { + // move the internal cursors + if (state.g.sourceMap) { + if (end < state.g.position) { + state.g.position = 0; + state.g.sourceLine = 1; + state.g.sourceColumn = 0; + } + + var source = state.g.source.substring(state.g.position, end); + var sourceLines = source.split('\n'); + if (sourceLines.length > 1) { + state.g.sourceLine += sourceLines.length - 1; + state.g.sourceColumn = 0; + } + state.g.sourceColumn += sourceLines[sourceLines.length - 1].length; + } + state.g.position = end; +} + +/** + * Appends a string of text to the buffer + * + * @param {string} str + * @param {object} state + */ +function append(str, state) { + if (state.g.sourceMap && str) { + state.g.sourceMap.addMapping({ + generated: { line: state.g.bufferLine, column: state.g.bufferColumn }, + original: { line: state.g.sourceLine, column: state.g.sourceColumn }, + source: state.g.sourceMapFilename + }); + var transformedLines = str.split('\n'); + if (transformedLines.length > 1) { + state.g.bufferLine += transformedLines.length - 1; + state.g.bufferColumn = 0; + } + state.g.bufferColumn += + transformedLines[transformedLines.length - 1].length; + } + state.g.buffer += str; +} + +/** + * Update indent using state.indentBy property. Indent is measured in + * double spaces. Updates a single line only. + * + * @param {string} str + * @param {object} state + * @return {string} + */ +function updateIndent(str, state) { + for (var i = 0; i < -state.g.indentBy; i++) { + str = str.replace(/(^|\n)( {2}|\t)/g, '$1'); + } + return str; +} + +/** + * Calculates indent from the beginning of the line until "start" or the first + * character before start. + * @example + * " foo.bar()" + * ^ + * start + * indent will be 2 + * + * @param {number} start + * @param {object} state + * @return {number} + */ +function indentBefore(start, state) { + var end = start; + start = start - 1; + + while (start > 0 && state.g.source[start] != '\n') { + if (!state.g.source[start].match(/[ \t]/)) { + end = start; + } + start--; + } + return state.g.source.substring(start + 1, end); +} + +function getDocblock(state) { + if (!state.g.docblock) { + var docblock = require('./docblock'); + state.g.docblock = + docblock.parseAsObject(docblock.extract(state.g.source)); + } + return state.g.docblock; +} + +function identWithinLexicalScope(identName, state, stopBeforeNode) { + var currScope = state.localScope; + while (currScope) { + if (currScope.identifiers[identName] !== undefined) { + return true; + } + + if (stopBeforeNode && currScope.parentNode === stopBeforeNode) { + break; + } + + currScope = currScope.parentScope; + } + return false; +} + +function identInLocalScope(identName, state) { + return state.localScope.identifiers[identName] !== undefined; +} + +function declareIdentInLocalScope(identName, state) { + state.localScope.identifiers[identName] = true; +} + +/** + * Apply the given analyzer function to the current node. If the analyzer + * doesn't return false, traverse each child of the current node using the given + * traverser function. + * + * @param {function} analyzer + * @param {function} traverser + * @param {object} node + * @param {function} visitor + * @param {array} path + * @param {object} state + */ +function analyzeAndTraverse(analyzer, traverser, node, path, state) { + var key, child; + + if (node.type) { + if (analyzer(node, path, state) === false) { + return; + } + path.unshift(node); + } + + for (key in node) { + // skip obviously wrong attributes + if (key === 'range' || key === 'loc') { + continue; + } + if (node.hasOwnProperty(key)) { + child = node[key]; + if (typeof child === 'object' && child !== null) { + traverser(child, path, state); + } + } + } + node.type && path.shift(); +} + +/** + * Checks whether a node or any of its sub-nodes contains + * a syntactic construct of the passed type. + * @param {object} node - AST node to test. + * @param {string} type - node type to lookup. + */ +function containsChildOfType(node, type) { + var foundMatchingChild = false; + function nodeTypeAnalyzer(node) { + if (node.type === type) { + foundMatchingChild = true; + return false; + } + } + function nodeTypeTraverser(child, path, state) { + if (!foundMatchingChild) { + foundMatchingChild = containsChildOfType(child, type); + } + } + analyzeAndTraverse( + nodeTypeAnalyzer, + nodeTypeTraverser, + node, + [] + ); + return foundMatchingChild; +} + +exports.append = append; +exports.catchup = catchup; +exports.catchupWhiteSpace = catchupWhiteSpace; +exports.catchupNewlines = catchupNewlines; +exports.containsChildOfType = containsChildOfType; +exports.createState = createState; +exports.declareIdentInLocalScope = declareIdentInLocalScope; +exports.getDocblock = getDocblock; +exports.identWithinLexicalScope = identWithinLexicalScope; +exports.identInLocalScope = identInLocalScope; +exports.indentBefore = indentBefore; +exports.move = move; +exports.updateIndent = updateIndent; +exports.updateState = updateState; +exports.analyzeAndTraverse = analyzeAndTraverse; + +},{"./docblock":17}],20:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*jslint node:true*/ + +/** + * @typechecks + */ +'use strict'; + +var base62 = require('base62'); +var Syntax = require('esprima-fb').Syntax; +var utils = require('../src/utils'); + +var SUPER_PROTO_IDENT_PREFIX = '____SuperProtoOf'; + +var _anonClassUUIDCounter = 0; +var _mungedSymbolMaps = {}; + +/** + * Used to generate a unique class for use with code-gens for anonymous class + * expressions. + * + * @param {object} state + * @return {string} + */ +function _generateAnonymousClassName(state) { + var mungeNamespace = state.mungeNamespace || ''; + return '____Class' + mungeNamespace + base62.encode(_anonClassUUIDCounter++); +} + +/** + * Given an identifier name, munge it using the current state's mungeNamespace. + * + * @param {string} identName + * @param {object} state + * @return {string} + */ +function _getMungedName(identName, state) { + var mungeNamespace = state.mungeNamespace; + var shouldMinify = state.g.opts.minify; + + if (shouldMinify) { + if (!_mungedSymbolMaps[mungeNamespace]) { + _mungedSymbolMaps[mungeNamespace] = { + symbolMap: {}, + identUUIDCounter: 0 + }; + } + + var symbolMap = _mungedSymbolMaps[mungeNamespace].symbolMap; + if (!symbolMap[identName]) { + symbolMap[identName] = + base62.encode(_mungedSymbolMaps[mungeNamespace].identUUIDCounter++); + } + identName = symbolMap[identName]; + } + return '$' + mungeNamespace + identName; +} + +/** + * Extracts super class information from a class node. + * + * Information includes name of the super class and/or the expression string + * (if extending from an expression) + * + * @param {object} node + * @param {object} state + * @return {object} + */ +function _getSuperClassInfo(node, state) { + var ret = { + name: null, + expression: null + }; + if (node.superClass) { + if (node.superClass.type === Syntax.Identifier) { + ret.name = node.superClass.name; + } else { + // Extension from an expression + ret.name = _generateAnonymousClassName(state); + ret.expression = state.g.source.substring( + node.superClass.range[0], + node.superClass.range[1] + ); + } + } + return ret; +} + +/** + * Used with .filter() to find the constructor method in a list of + * MethodDefinition nodes. + * + * @param {object} classElement + * @return {boolean} + */ +function _isConstructorMethod(classElement) { + return classElement.type === Syntax.MethodDefinition && + classElement.key.type === Syntax.Identifier && + classElement.key.name === 'constructor'; +} + +/** + * @param {object} node + * @param {object} state + * @return {boolean} + */ +function _shouldMungeIdentifier(node, state) { + return ( + !!state.methodFuncNode && + !utils.getDocblock(state).hasOwnProperty('preventMunge') && + /^_(?!_)/.test(node.name) + ); +} + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function visitClassMethod(traverse, node, path, state) { + utils.catchup(node.range[0], state); + path.unshift(node); + traverse(node.value, path, state); + path.shift(); + return false; +} +visitClassMethod.test = function(node, path, state) { + return node.type === Syntax.MethodDefinition; +}; + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function visitClassFunctionExpression(traverse, node, path, state) { + var methodNode = path[0]; + + state = utils.updateState(state, { + methodFuncNode: node + }); + + if (methodNode.key.name === 'constructor') { + utils.append('function ' + state.className, state); + } else { + var methodName = methodNode.key.name; + if (_shouldMungeIdentifier(methodNode.key, state)) { + methodName = _getMungedName(methodName, state); + } + + var prototypeOrStatic = methodNode.static ? '' : 'prototype.'; + utils.append( + state.className + '.' + prototypeOrStatic + methodName + '=function', + state + ); + } + utils.move(methodNode.key.range[1], state); + + var params = node.params; + var paramName; + if (params.length > 0) { + for (var i = 0; i < params.length; i++) { + utils.catchup(node.params[i].range[0], state); + paramName = params[i].name; + if (_shouldMungeIdentifier(params[i], state)) { + paramName = _getMungedName(params[i].name, state); + } + utils.append(paramName, state); + utils.move(params[i].range[1], state); + } + } else { + utils.append('(', state); + } + utils.append(')', state); + utils.catchupWhiteSpace(node.body.range[0], state); + utils.append('{', state); + if (!state.scopeIsStrict) { + utils.append('"use strict";', state); + } + utils.move(node.body.range[0] + '{'.length, state); + + path.unshift(node); + traverse(node.body, path, state); + path.shift(); + utils.catchup(node.body.range[1], state); + + if (methodNode.key.name !== 'constructor') { + utils.append(';', state); + } + return false; +} +visitClassFunctionExpression.test = function(node, path, state) { + return node.type === Syntax.FunctionExpression + && path[0].type === Syntax.MethodDefinition; +}; + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function _renderClassBody(traverse, node, path, state) { + var className = state.className; + var superClass = state.superClass; + + // Set up prototype of constructor on same line as `extends` for line-number + // preservation. This relies on function-hoisting if a constructor function is + // defined in the class body. + if (superClass.name) { + // If the super class is an expression, we need to memoize the output of the + // expression into the generated class name variable and use that to refer + // to the super class going forward. Example: + // + // class Foo extends mixin(Bar, Baz) {} + // --transforms to-- + // function Foo() {} var ____Class0Blah = mixin(Bar, Baz); + if (superClass.expression !== null) { + utils.append( + 'var ' + superClass.name + '=' + superClass.expression + ';', + state + ); + } + + var keyName = superClass.name + '____Key'; + var keyNameDeclarator = ''; + if (!utils.identWithinLexicalScope(keyName, state)) { + keyNameDeclarator = 'var '; + utils.declareIdentInLocalScope(keyName, state); + } + utils.append( + 'for(' + keyNameDeclarator + keyName + ' in ' + superClass.name + '){' + + 'if(' + superClass.name + '.hasOwnProperty(' + keyName + ')){' + + className + '[' + keyName + ']=' + + superClass.name + '[' + keyName + '];' + + '}' + + '}', + state + ); + + var superProtoIdentStr = SUPER_PROTO_IDENT_PREFIX + superClass.name; + if (!utils.identWithinLexicalScope(superProtoIdentStr, state)) { + utils.append( + 'var ' + superProtoIdentStr + '=' + superClass.name + '===null?' + + 'null:' + superClass.name + '.prototype;', + state + ); + utils.declareIdentInLocalScope(superProtoIdentStr, state); + } + + utils.append( + className + '.prototype=Object.create(' + superProtoIdentStr + ');', + state + ); + utils.append( + className + '.prototype.constructor=' + className + ';', + state + ); + utils.append( + className + '.__superConstructor__=' + superClass.name + ';', + state + ); + } + + // If there's no constructor method specified in the class body, create an + // empty constructor function at the top (same line as the class keyword) + if (!node.body.body.filter(_isConstructorMethod).pop()) { + utils.append('function ' + className + '(){', state); + if (!state.scopeIsStrict) { + utils.append('"use strict";', state); + } + if (superClass.name) { + utils.append( + 'if(' + superClass.name + '!==null){' + + superClass.name + '.apply(this,arguments);}', + state + ); + } + utils.append('}', state); + } + + utils.move(node.body.range[0] + '{'.length, state); + traverse(node.body, path, state); + utils.catchupWhiteSpace(node.range[1], state); +} + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function visitClassDeclaration(traverse, node, path, state) { + var className = node.id.name; + var superClass = _getSuperClassInfo(node, state); + + state = utils.updateState(state, { + mungeNamespace: className, + className: className, + superClass: superClass + }); + + _renderClassBody(traverse, node, path, state); + + return false; +} +visitClassDeclaration.test = function(node, path, state) { + return node.type === Syntax.ClassDeclaration; +}; + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function visitClassExpression(traverse, node, path, state) { + var className = node.id && node.id.name || _generateAnonymousClassName(state); + var superClass = _getSuperClassInfo(node, state); + + utils.append('(function(){', state); + + state = utils.updateState(state, { + mungeNamespace: className, + className: className, + superClass: superClass + }); + + _renderClassBody(traverse, node, path, state); + + utils.append('return ' + className + ';})()', state); + return false; +} +visitClassExpression.test = function(node, path, state) { + return node.type === Syntax.ClassExpression; +}; + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function visitPrivateIdentifier(traverse, node, path, state) { + utils.append(_getMungedName(node.name, state), state); + utils.move(node.range[1], state); +} +visitPrivateIdentifier.test = function(node, path, state) { + if (node.type === Syntax.Identifier && _shouldMungeIdentifier(node, state)) { + // Always munge non-computed properties of MemberExpressions + // (a la preventing access of properties of unowned objects) + if (path[0].type === Syntax.MemberExpression && path[0].object !== node + && path[0].computed === false) { + return true; + } + + // Always munge identifiers that were declared within the method function + // scope + if (utils.identWithinLexicalScope(node.name, state, state.methodFuncNode)) { + return true; + } + + // Always munge private keys on object literals defined within a method's + // scope. + if (path[0].type === Syntax.Property + && path[1].type === Syntax.ObjectExpression) { + return true; + } + + // Always munge function parameters + if (path[0].type === Syntax.FunctionExpression + || path[0].type === Syntax.FunctionDeclaration) { + for (var i = 0; i < path[0].params.length; i++) { + if (path[0].params[i] === node) { + return true; + } + } + } + } + return false; +}; + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function visitSuperCallExpression(traverse, node, path, state) { + var superClassName = state.superClass.name; + + if (node.callee.type === Syntax.Identifier) { + utils.append(superClassName + '.call(', state); + utils.move(node.callee.range[1], state); + } else if (node.callee.type === Syntax.MemberExpression) { + utils.append(SUPER_PROTO_IDENT_PREFIX + superClassName, state); + utils.move(node.callee.object.range[1], state); + + if (node.callee.computed) { + // ["a" + "b"] + utils.catchup(node.callee.property.range[1] + ']'.length, state); + } else { + // .ab + utils.append('.' + node.callee.property.name, state); + } + + utils.append('.call(', state); + utils.move(node.callee.range[1], state); + } + + utils.append('this', state); + if (node.arguments.length > 0) { + utils.append(',', state); + utils.catchupWhiteSpace(node.arguments[0].range[0], state); + traverse(node.arguments, path, state); + } + + utils.catchupWhiteSpace(node.range[1], state); + utils.append(')', state); + return false; +} +visitSuperCallExpression.test = function(node, path, state) { + if (state.superClass && node.type === Syntax.CallExpression) { + var callee = node.callee; + if (callee.type === Syntax.Identifier && callee.name === 'super' + || callee.type == Syntax.MemberExpression + && callee.object.name === 'super') { + return true; + } + } + return false; +}; + +/** + * @param {function} traverse + * @param {object} node + * @param {array} path + * @param {object} state + */ +function visitSuperMemberExpression(traverse, node, path, state) { + var superClassName = state.superClass.name; + + utils.append(SUPER_PROTO_IDENT_PREFIX + superClassName, state); + utils.move(node.object.range[1], state); +} +visitSuperMemberExpression.test = function(node, path, state) { + return state.superClass + && node.type === Syntax.MemberExpression + && node.object.type === Syntax.Identifier + && node.object.name === 'super'; +}; + +exports.visitorList = [ + visitClassDeclaration, + visitClassExpression, + visitClassFunctionExpression, + visitClassMethod, + visitPrivateIdentifier, + visitSuperCallExpression, + visitSuperMemberExpression +]; + +},{"../src/utils":19,"base62":6,"esprima-fb":5}],21:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* jshint browser: true */ +/* jslint evil: true */ + +'use strict'; +var runScripts; +var headEl; + +var transform = require('jstransform').transform; +var visitors = require('./fbtransform/visitors').transformVisitors; +var transform = transform.bind(null, visitors.react); +var docblock = require('jstransform/src/docblock'); + + +exports.transform = transform; + +exports.exec = function(code) { + return eval(transform(code).code); +}; + +if (typeof window === "undefined" || window === null) { + return; +} +headEl = document.getElementsByTagName('head')[0]; + +var run = exports.run = function(code) { + var jsx = docblock.parseAsObject(docblock.extract(code)).jsx; + + var functionBody = jsx ? transform(code).code : code; + var scriptEl = document.createElement('script'); + + scriptEl.text = functionBody; + headEl.appendChild(scriptEl); +}; + +var load = exports.load = function(url, callback) { + var xhr; + xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') + : new XMLHttpRequest(); + + // Disable async since we need to execute scripts in the order they are in the + // DOM to mirror normal script loading. + xhr.open('GET', url, false); + if ('overrideMimeType' in xhr) { + xhr.overrideMimeType('text/plain'); + } + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if (xhr.status === 0 || xhr.status === 200) { + run(xhr.responseText); + } else { + throw new Error("Could not load " + url); + } + if (callback) { + return callback(); + } + } + }; + return xhr.send(null); +}; + +runScripts = function() { + var scripts = document.getElementsByTagName('script'); + + // Array.prototype.slice cannot be used on NodeList on IE8 + var jsxScripts = []; + for (var i = 0; i < scripts.length; i++) { + if (scripts.item(i).type === 'text/jsx') { + jsxScripts.push(scripts.item(i)); + } + } + + console.warn("You are using the in-browser JSX transformer. Be sure to precompile your JSX for production - http://facebook.github.io/react/docs/tooling-integration.html#jsx"); + + jsxScripts.forEach(function(script) { + if (script.src) { + load(script.src); + } else { + run(script.innerHTML); + } + }); +}; + +if (window.addEventListener) { + window.addEventListener('DOMContentLoaded', runScripts, false); +} else { + window.attachEvent('onload', runScripts); +} + +},{"./fbtransform/visitors":25,"jstransform":18,"jstransform/src/docblock":17}],22:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +"use strict"; + +var Syntax = require('esprima-fb').Syntax; +var utils = require('jstransform/src/utils'); + +var FALLBACK_TAGS = require('./xjs').knownTags; +var renderXJSExpressionContainer = + require('./xjs').renderXJSExpressionContainer; +var renderXJSLiteral = require('./xjs').renderXJSLiteral; +var quoteAttrName = require('./xjs').quoteAttrName; + +/** + * Customized desugar processor. + * + * Currently: (Somewhat tailored to React) + * => X(null, null) + * => X({prop: '1'}, null) + * => X({prop:'2'}, Y(null, null)) + * => X({prop:'2'}, [Y(null, null), Z(null, null)]) + * + * Exceptions to the simple rules above: + * if a property is named "class" it will be changed to "className" in the + * javascript since "class" is not a valid object key in javascript. + */ + +var JSX_ATTRIBUTE_TRANSFORMS = { + cxName: function(attr) { + if (attr.value.type !== Syntax.Literal) { + throw new Error("cx only accepts a string literal"); + } else { + var classNames = attr.value.value.split(/\s+/g); + return 'cx(' + classNames.map(JSON.stringify).join(',') + ')'; + } + } +}; + +function visitReactTag(traverse, object, path, state) { + var jsxObjIdent = utils.getDocblock(state).jsx; + + utils.catchup(object.openingElement.range[0], state); + + if (object.name.namespace) { + throw new Error( + 'Namespace tags are not supported. ReactJSX is not XML.'); + } + + var isFallbackTag = FALLBACK_TAGS[object.name.name]; + utils.append( + (isFallbackTag ? jsxObjIdent + '.' : '') + (object.name.name) + '(', + state + ); + + utils.move(object.name.range[1], state); + + var childrenToRender = object.children.filter(function(child) { + return !(child.type === Syntax.Literal && !child.value.match(/\S/)); + }); + + // if we don't have any attributes, pass in null + if (object.attributes.length === 0) { + utils.append('null', state); + } + + // write attributes + object.attributes.forEach(function(attr, index) { + utils.catchup(attr.range[0], state); + if (attr.name.namespace) { + throw new Error( + 'Namespace attributes are not supported. ReactJSX is not XML.'); + } + var name = attr.name.name; + var isFirst = index === 0; + var isLast = index === object.attributes.length - 1; + + if (isFirst) { + utils.append('{', state); + } + + utils.append(quoteAttrName(name), state); + utils.append(':', state); + + if (!attr.value) { + state.g.buffer += 'true'; + state.g.position = attr.name.range[1]; + if (!isLast) { + utils.append(',', state); + } + } else { + utils.move(attr.name.range[1], state); + // Use catchupWhiteSpace to skip over the '=' in the attribute + utils.catchupWhiteSpace(attr.value.range[0], state); + if (JSX_ATTRIBUTE_TRANSFORMS[attr.name.name]) { + utils.append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state); + utils.move(attr.value.range[1], state); + if (!isLast) { + utils.append(',', state); + } + } else if (attr.value.type === Syntax.Literal) { + renderXJSLiteral(attr.value, isLast, state); + } else { + renderXJSExpressionContainer(traverse, attr.value, isLast, path, state); + } + } + + if (isLast) { + utils.append('}', state); + } + + utils.catchup(attr.range[1], state); + }); + + if (!object.selfClosing) { + utils.catchup(object.openingElement.range[1] - 1, state); + utils.move(object.openingElement.range[1], state); + } + + // filter out whitespace + if (childrenToRender.length > 0) { + utils.append(', ', state); + + object.children.forEach(function(child) { + if (child.type === Syntax.Literal && !child.value.match(/\S/)) { + return; + } + utils.catchup(child.range[0], state); + + var isLast = child === childrenToRender[childrenToRender.length - 1]; + + if (child.type === Syntax.Literal) { + renderXJSLiteral(child, isLast, state); + } else if (child.type === Syntax.XJSExpressionContainer) { + renderXJSExpressionContainer(traverse, child, isLast, path, state); + } else { + traverse(child, path, state); + if (!isLast) { + utils.append(',', state); + state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1'); + } + } + + utils.catchup(child.range[1], state); + }); + } + + if (object.selfClosing) { + // everything up to /> + utils.catchup(object.openingElement.range[1] - 2, state); + utils.move(object.openingElement.range[1], state); + } else { + // everything up to + utils.catchup(object.closingElement.range[0], state); + utils.move(object.closingElement.range[1], state); + } + + utils.append(')', state); + return false; +} + +visitReactTag.test = function(object, path, state) { + // only run react when react @jsx namespace is specified in docblock + var jsx = utils.getDocblock(state).jsx; + return object.type === Syntax.XJSElement && jsx && jsx.length; +}; + +exports.visitReactTag = visitReactTag; + +},{"./xjs":24,"esprima-fb":5,"jstransform/src/utils":19}],23:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +"use strict"; + +var Syntax = require('esprima-fb').Syntax; +var utils = require('jstransform/src/utils'); + +/** + * Transforms the following: + * + * var MyComponent = React.createClass({ + * render: ... + * }); + * + * into: + * + * var MyComponent = React.createClass({ + * displayName: 'MyComponent', + * render: ... + * }); + */ +function visitReactDisplayName(traverse, object, path, state) { + if (object.id.type === Syntax.Identifier && + object.init && + object.init.type === Syntax.CallExpression && + object.init.callee.type === Syntax.MemberExpression && + object.init.callee.object.type === Syntax.Identifier && + object.init.callee.object.name === 'React' && + object.init.callee.property.type === Syntax.Identifier && + object.init.callee.property.name === 'createClass' && + object.init['arguments'].length === 1 && + object.init['arguments'][0].type === Syntax.ObjectExpression) { + + var displayName = object.id.name; + utils.catchup(object.init['arguments'][0].range[0] + 1, state); + utils.append("displayName: '" + displayName + "',", state); + } +} + +/** + * Will only run on @jsx files for now. + */ +visitReactDisplayName.test = function(object, path, state) { + return object.type === Syntax.VariableDeclarator && !!utils.getDocblock(state).jsx; +}; + +exports.visitReactDisplayName = visitReactDisplayName; + +},{"esprima-fb":5,"jstransform/src/utils":19}],24:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global exports:true*/ +"use strict"; +var append = require('jstransform/src/utils').append; +var catchup = require('jstransform/src/utils').catchup; +var move = require('jstransform/src/utils').move; +var Syntax = require('esprima-fb').Syntax; + +var knownTags = { + a: true, + abbr: true, + address: true, + applet: true, + area: true, + article: true, + aside: true, + audio: true, + b: true, + base: true, + bdi: true, + bdo: true, + big: true, + blockquote: true, + body: true, + br: true, + button: true, + canvas: true, + caption: true, + circle: true, + cite: true, + code: true, + col: true, + colgroup: true, + command: true, + data: true, + datalist: true, + dd: true, + del: true, + details: true, + dfn: true, + dialog: true, + div: true, + dl: true, + dt: true, + ellipse: true, + em: true, + embed: true, + fieldset: true, + figcaption: true, + figure: true, + footer: true, + form: true, + g: true, + h1: true, + h2: true, + h3: true, + h4: true, + h5: true, + h6: true, + head: true, + header: true, + hgroup: true, + hr: true, + html: true, + i: true, + iframe: true, + img: true, + input: true, + ins: true, + kbd: true, + keygen: true, + label: true, + legend: true, + li: true, + line: true, + link: true, + main: true, + map: true, + mark: true, + marquee: true, + menu: true, + menuitem: true, + meta: true, + meter: true, + nav: true, + noscript: true, + object: true, + ol: true, + optgroup: true, + option: true, + output: true, + p: true, + param: true, + path: true, + polyline: true, + pre: true, + progress: true, + q: true, + rect: true, + rp: true, + rt: true, + ruby: true, + s: true, + samp: true, + script: true, + section: true, + select: true, + small: true, + source: true, + span: true, + strong: true, + style: true, + sub: true, + summary: true, + sup: true, + svg: true, + table: true, + tbody: true, + td: true, + text: true, + textarea: true, + tfoot: true, + th: true, + thead: true, + time: true, + title: true, + tr: true, + track: true, + u: true, + ul: true, + 'var': true, + video: true, + wbr: true +}; + +function safeTrim(string) { + return string.replace(/^[ \t]+/, '').replace(/[ \t]+$/, ''); +} + +// Replace all trailing whitespace characters with a single space character +function trimWithSingleSpace(string) { + return string.replace(/^[ \t\xA0]{2,}/, ' '). + replace(/[ \t\xA0]{2,}$/, ' ').replace(/^\s+$/, ''); +} + +/** + * Special handling for multiline string literals + * print lines: + * + * line + * line + * + * as: + * + * "line "+ + * "line" + */ +function renderXJSLiteral(object, isLast, state, start, end) { + /** Added blank check filtering and triming*/ + var trimmedChildValue = safeTrim(object.value); + var hasFinalNewLine = false; + + if (trimmedChildValue) { + // head whitespace + append(object.value.match(/^[\t ]*/)[0], state); + if (start) { + append(start, state); + } + + var trimmedChildValueWithSpace = trimWithSingleSpace(object.value); + + /** + */ + var initialLines = trimmedChildValue.split(/\r\n|\n|\r/); + + var lines = initialLines.filter(function(line) { + return safeTrim(line).length > 0; + }); + + var hasInitialNewLine = initialLines[0] !== lines[0]; + hasFinalNewLine = + initialLines[initialLines.length - 1] !== lines[lines.length - 1]; + + var numLines = lines.length; + lines.forEach(function (line, ii) { + var lastLine = ii === numLines - 1; + var trimmedLine = safeTrim(line); + if (trimmedLine === '' && !lastLine) { + append(line, state); + } else { + var preString = ''; + var postString = ''; + var leading = line.match(/^[ \t]*/)[0]; + + if (ii === 0) { + if (hasInitialNewLine) { + preString = ' '; + leading = '\n' + leading; + } + if (trimmedChildValueWithSpace.substring(0, 1) === ' ') { + // If this is the first line, and the original content starts with + // whitespace, place a single space at the beginning. + preString = ' '; + } + } + if (!lastLine || trimmedChildValueWithSpace.substr( + trimmedChildValueWithSpace.length - 1, 1) === ' ' || + hasFinalNewLine + ) { + // If either not on the last line, or the original content ends with + // whitespace, place a single character at the end. + postString = ' '; + } + + append( + leading + + JSON.stringify( + preString + trimmedLine + postString + ) + + (lastLine ? '' : '+') + + line.match(/[ \t]*$/)[0], + state); + } + if (!lastLine) { + append('\n', state); + } + }); + } else { + if (start) { + append(start, state); + } + append('""', state); + } + if (end) { + append(end, state); + } + + // add comma before trailing whitespace + if (!isLast) { + append(',', state); + } + + // tail whitespace + if (hasFinalNewLine) { + append('\n', state); + } + append(object.value.match(/[ \t]*$/)[0], state); + move(object.range[1], state); +} + +function renderXJSExpressionContainer(traverse, object, isLast, path, state) { + // Plus 1 to skip `{`. + move(object.range[0] + 1, state); + traverse(object.expression, path, state); + if (!isLast && object.expression.type !== Syntax.XJSEmptyExpression) { + // If we need to append a comma, make sure to do so after the expression. + catchup(object.expression.range[1], state); + append(',', state); + } + + // Minus 1 to skip `}`. + catchup(object.range[1] - 1, state); + move(object.range[1], state); + return false; +} + +function quoteAttrName(attr) { + // Quote invalid JS identifiers. + if (!/^[a-z_$][a-z\d_$]*$/i.test(attr)) { + return "'" + attr + "'"; + } + return attr; +} + +exports.knownTags = knownTags; +exports.renderXJSExpressionContainer = renderXJSExpressionContainer; +exports.renderXJSLiteral = renderXJSLiteral; +exports.quoteAttrName = quoteAttrName; + +},{"esprima-fb":5,"jstransform/src/utils":19}],25:[function(require,module,exports){ +/*global exports:true*/ +var es6Classes = require('jstransform/visitors/es6-class-visitors').visitorList; +var react = require('./transforms/react'); +var reactDisplayName = require('./transforms/reactDisplayName'); + +/** + * Map from transformName => orderedListOfVisitors. + */ +var transformVisitors = { + 'es6-classes': es6Classes, + 'react': [ + react.visitReactTag, + reactDisplayName.visitReactDisplayName + ] +}; + +/** + * Specifies the order in which each transform should run. + */ +var transformRunOrder = [ + 'es6-classes', + 'react' +]; + +/** + * Given a list of transform names, return the ordered list of visitors to be + * passed to the transform() function. + * + * @param {array?} excludes + * @return {array} + */ +function getVisitorsList(excludes) { + var ret = []; + for (var i = 0, il = transformRunOrder.length; i < il; i++) { + if (!excludes || excludes.indexOf(transformRunOrder[i]) === -1) { + ret = ret.concat(transformVisitors[transformRunOrder[i]]); + } + } + return ret; +} + +exports.getVisitorsList = getVisitorsList; +exports.transformVisitors = transformVisitors; + +},{"./transforms/react":22,"./transforms/reactDisplayName":23,"jstransform/visitors/es6-class-visitors":20}]},{},[21]) +(21) +}); +; \ No newline at end of file diff --git a/third_party/react/LICENSE.txt b/third_party/react/LICENSE.txt new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/third_party/react/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/react/README.md b/third_party/react/README.md new file mode 100644 index 000000000..0e71e7b7f --- /dev/null +++ b/third_party/react/README.md @@ -0,0 +1,98 @@ +# [React](http://facebook.github.io/react) [![Build Status](https://travis-ci.org/facebook/react.png?branch=master)](https://travis-ci.org/facebook/react) + +React is a JavaScript library for building user interfaces. + +* **Just the UI:** Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project. +* **Virtual DOM:** React uses a *virtual DOM* diff implementation for ultra-high performance. It can also render on the server using Node.js — no heavy browser DOM required. +* **Data flow:** React implements one-way reactive data flow which reduces boilerplate and is easier to reason about than traditional data binding. + +[Learn how to use React in your own project.](http://facebook.github.io/react/docs/getting-started.html) + +## The `react` npm package has recently changed! + +If you're looking for jeffbski's [React.js](https://github.com/jeffbski/react) project, it's now in `npm` as `reactjs` rather than `react`. + +## Examples + +We have several examples [on the website](http://facebook.github.io/react/). Here is the first one to get you started: + +```js +/** @jsx React.DOM */ +var HelloMessage = React.createClass({ + render: function() { + return
Hello {this.props.name}
; + } +}); + +React.renderComponent( + , + document.getElementById('container') +); +``` + +This example will render "Hello John" into a container on the page. + +You'll notice that we used an XML-like syntax; [we call it JSX](http://facebook.github.io/react/docs/jsx-in-depth.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. A simple transform is included with React that allows converting JSX into native JavaScript for browsers to digest. + +## Installation + +The fastest way to get started is to serve JavaScript from the CDN (also available on [CDNJS](http://cdnjs.com/#react)): + +```html + + + + +``` + +We've also built a [starter kit](http://facebook.github.io/react/downloads/react-0.8.0.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code. + +If you'd like to use [bower](http://bower.io), it's as easy as: + +```sh +bower install --save react +``` + +## Contribute + +The main purpose of this repository is to continue to evolve React core, making it faster and easier to use. If you're interested in helping with that, then keep reading. If you're not interested in helping right now that's ok too. :) Any feedback you have about using React would be greatly appreciated. + +### Building Your Copy of React + +The process to build `react.js` is built entirely on top of node.js, using many libraries you may already be familiar with. + +#### Prerequisites + +* You have `node` installed at v0.10.0+ (it might work at lower versions, we just haven't tested). +* You are familiar with `npm` and know whether or not you need to use `sudo` when installing packages globally. +* You are familiar with `git`. + +#### Build + +Once you have the repository cloned, building a copy of `react.js` is really easy. + +```sh +# grunt-cli is needed by grunt; you might have this installed already +npm install -g grunt-cli +npm install +grunt build +``` + +At this point, you should now have a `build/` directory populated with everything you need to use React. The examples should all work. + +### Grunt + +We use grunt to automate many tasks. Run `grunt -h` to see a mostly complete listing. The important ones to know: + +```sh +# Build and run tests with PhantomJS +grunt test +# Lint the code with JSHint +grunt lint +# Wipe out build directory +grunt clean +``` + +### More… + +There's only so much we can cram in here. To read more about the community and guidelines for submitting pull requests, please read the [Contributing document](CONTRIBUTING.md). diff --git a/third_party/react/VERSION.txt b/third_party/react/VERSION.txt new file mode 100644 index 000000000..a3df0a695 --- /dev/null +++ b/third_party/react/VERSION.txt @@ -0,0 +1 @@ +0.8.0 diff --git a/third_party/react/react-with-addons.js b/third_party/react/react-with-addons.js new file mode 100644 index 000000000..fca1fe462 --- /dev/null +++ b/third_party/react/react-with-addons.js @@ -0,0 +1,15505 @@ +/** + * React (with addons) v0.8.0 + */ +!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.React=e():"undefined"!=typeof global?global.React=e():"undefined"!=typeof self&&(self.React=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1; +} + +var CSSCore = { + + /** + * Adds the class passed in to the element if it doesn't already have it. + * + * @param {DOMElement} element the element to set the class on + * @param {string} className the CSS className + * @return {DOMElement} the element passed in + */ + addClass: function(element, className) { + ("production" !== "development" ? invariant( + !/\s/.test(className), + 'CSSCore.addClass takes only a single class name. "%s" contains ' + + 'multiple classes.', className + ) : invariant(!/\s/.test(className))); + + if (className) { + if (element.classList) { + element.classList.add(className); + } else if (!hasClass(element, className)) { + element.className = element.className + ' ' + className; + } + } + return element; + }, + + /** + * Removes the class passed in from the element + * + * @param {DOMElement} element the element to set the class on + * @param {string} className the CSS className + * @return {DOMElement} the element passed in + */ + removeClass: function(element, className) { + ("production" !== "development" ? invariant( + !/\s/.test(className), + 'CSSCore.removeClass takes only a single class name. "%s" contains ' + + 'multiple classes.', className + ) : invariant(!/\s/.test(className))); + + if (className) { + if (element.classList) { + element.classList.remove(className); + } else if (hasClass(element, className)) { + element.className = element.className + .replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1') + .replace(/\s+/g, ' ') // multiple spaces to one + .replace(/^\s*|\s*$/g, ''); // trim the ends + } + } + return element; + }, + + /** + * Helper to add or remove a class from an element based on a condition. + * + * @param {DOMElement} element the element to set the class on + * @param {string} className the CSS className + * @param {*} bool condition to whether to add or remove the class + * @return {DOMElement} the element passed in + */ + conditionClass: function(element, className, bool) { + return (bool ? CSSCore.addClass : CSSCore.removeClass)(element, className); + } +}; + +module.exports = CSSCore; + +},{"./invariant":109}],3:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CSSProperty + */ + +"use strict"; + +/** + * CSS properties which accept numbers but are not in units of "px". + */ +var isUnitlessNumber = { + fillOpacity: true, + fontWeight: true, + lineHeight: true, + opacity: true, + orphans: true, + zIndex: true, + zoom: true +}; + +/** + * Most style properties can be unset by doing .style[prop] = '' but IE8 + * doesn't like doing that with shorthand properties so for the properties that + * IE8 breaks on, which are listed here, we instead unset each of the + * individual properties. See http://bugs.jquery.com/ticket/12385. + * The 4-value 'clock' properties like margin, padding, border-width seem to + * behave without any problems. Curiously, list-style works too without any + * special prodding. + */ +var shorthandPropertyExpansions = { + background: { + backgroundImage: true, + backgroundPosition: true, + backgroundRepeat: true, + backgroundColor: true + }, + border: { + borderWidth: true, + borderStyle: true, + borderColor: true + }, + borderBottom: { + borderBottomWidth: true, + borderBottomStyle: true, + borderBottomColor: true + }, + borderLeft: { + borderLeftWidth: true, + borderLeftStyle: true, + borderLeftColor: true + }, + borderRight: { + borderRightWidth: true, + borderRightStyle: true, + borderRightColor: true + }, + borderTop: { + borderTopWidth: true, + borderTopStyle: true, + borderTopColor: true + }, + font: { + fontStyle: true, + fontVariant: true, + fontWeight: true, + fontSize: true, + lineHeight: true, + fontFamily: true + } +}; + +var CSSProperty = { + isUnitlessNumber: isUnitlessNumber, + shorthandPropertyExpansions: shorthandPropertyExpansions +}; + +module.exports = CSSProperty; + +},{}],4:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CSSPropertyOperations + * @typechecks static-only + */ + +"use strict"; + +var CSSProperty = require("./CSSProperty"); + +var dangerousStyleValue = require("./dangerousStyleValue"); +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var hyphenate = require("./hyphenate"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +var processStyleName = memoizeStringOnly(function(styleName) { + return escapeTextForBrowser(hyphenate(styleName)); +}); + +/** + * Operations for dealing with CSS properties. + */ +var CSSPropertyOperations = { + + /** + * Serializes a mapping of style properties for use as inline styles: + * + * > createMarkupForStyles({width: '200px', height: 0}) + * "width:200px;height:0;" + * + * Undefined values are ignored so that declarative programming is easier. + * + * @param {object} styles + * @return {?string} + */ + createMarkupForStyles: function(styles) { + var serialized = ''; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = styles[styleName]; + if (styleValue != null) { + serialized += processStyleName(styleName) + ':'; + serialized += dangerousStyleValue(styleName, styleValue) + ';'; + } + } + return serialized || null; + }, + + /** + * Sets the value for multiple styles on a node. If a value is specified as + * '' (empty string), the corresponding style property will be unset. + * + * @param {DOMElement} node + * @param {object} styles + */ + setValueForStyles: function(node, styles) { + var style = node.style; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = dangerousStyleValue(styleName, styles[styleName]); + if (styleValue) { + style[styleName] = styleValue; + } else { + var expansion = CSSProperty.shorthandPropertyExpansions[styleName]; + if (expansion) { + // Shorthand property that IE8 won't like unsetting, so unset each + // component to placate it + for (var individualStyleName in expansion) { + style[individualStyleName] = ''; + } + } else { + style[styleName] = ''; + } + } + } + } + +}; + +module.exports = CSSPropertyOperations; + +},{"./CSSProperty":3,"./dangerousStyleValue":93,"./escapeTextForBrowser":95,"./hyphenate":108,"./memoizeStringOnly":117}],5:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CallbackRegistry + * @typechecks static-only + */ + +"use strict"; + +var listenerBank = {}; + +/** + * Stores "listeners" by `registrationName`/`id`. There should be at most one + * "listener" per `registrationName`/`id` in the `listenerBank`. + * + * Access listeners via `listenerBank[registrationName][id]`. + * + * @class CallbackRegistry + * @internal + */ +var CallbackRegistry = { + + /** + * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {?function} listener The callback to store. + */ + putListener: function(id, registrationName, listener) { + var bankForRegistrationName = + listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[id] = listener; + }, + + /** + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ + getListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + return bankForRegistrationName && bankForRegistrationName[id]; + }, + + /** + * Deletes a listener from the registration bank. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + */ + deleteListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + if (bankForRegistrationName) { + delete bankForRegistrationName[id]; + } + }, + + /** + * Deletes all listeners for the DOM element with the supplied ID. + * + * @param {string} id ID of the DOM element. + */ + deleteAllListeners: function(id) { + for (var registrationName in listenerBank) { + delete listenerBank[registrationName][id]; + } + }, + + /** + * This is needed for tests only. Do not use! + */ + __purge: function() { + listenerBank = {}; + } + +}; + +module.exports = CallbackRegistry; + +},{}],6:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ChangeEventPlugin + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var EventPluginHub = require("./EventPluginHub"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var SyntheticEvent = require("./SyntheticEvent"); + +var isEventSupported = require("./isEventSupported"); +var isTextInputElement = require("./isTextInputElement"); +var keyOf = require("./keyOf"); + +var topLevelTypes = EventConstants.topLevelTypes; + +var eventTypes = { + change: { + phasedRegistrationNames: { + bubbled: keyOf({onChange: null}), + captured: keyOf({onChangeCapture: null}) + } + } +}; + +/** + * For IE shims + */ +var activeElement = null; +var activeElementID = null; +var activeElementValue = null; +var activeElementValueProp = null; + +/** + * SECTION: handle `change` event + */ +function shouldUseChangeEvent(elem) { + return ( + elem.nodeName === 'SELECT' || + (elem.nodeName === 'INPUT' && elem.type === 'file') + ); +} + +var doesChangeEventBubble = false; +if (ExecutionEnvironment.canUseDOM) { + // See `handleChange` comment below + doesChangeEventBubble = isEventSupported('change') && ( + !('documentMode' in document) || document.documentMode > 8 + ); +} + +function manualDispatchChangeEvent(nativeEvent) { + var event = SyntheticEvent.getPooled( + eventTypes.change, + activeElementID, + nativeEvent + ); + EventPropagators.accumulateTwoPhaseDispatches(event); + + // If change bubbled, we'd just bind to it like all the other events + // and have it go through ReactEventTopLevelCallback. Since it doesn't, we + // manually listen for the change event and so we have to enqueue and + // process the abstract event manually. + EventPluginHub.enqueueEvents(event); + EventPluginHub.processEventQueue(); +} + +function startWatchingForChangeEventIE8(target, targetID) { + activeElement = target; + activeElementID = targetID; + activeElement.attachEvent('onchange', manualDispatchChangeEvent); +} + +function stopWatchingForChangeEventIE8() { + if (!activeElement) { + return; + } + activeElement.detachEvent('onchange', manualDispatchChangeEvent); + activeElement = null; + activeElementID = null; +} + +function getTargetIDForChangeEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topChange) { + return topLevelTargetID; + } +} +function handleEventsForChangeEventIE8( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topFocus) { + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForChangeEventIE8(); + startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID); + } else if (topLevelType === topLevelTypes.topBlur) { + stopWatchingForChangeEventIE8(); + } +} + + +/** + * SECTION: handle `input` event + */ +var isInputEventSupported = false; +if (ExecutionEnvironment.canUseDOM) { + // IE9 claims to support the input event but fails to trigger it when + // deleting text, so we ignore its input events + isInputEventSupported = isEventSupported('input') && ( + !('documentMode' in document) || document.documentMode > 9 + ); +} + +/** + * (For old IE.) Replacement getter/setter for the `value` property that gets + * set on the active element. + */ +var newValueProp = { + get: function() { + return activeElementValueProp.get.call(this); + }, + set: function(val) { + // Cast to a string so we can do equality checks. + activeElementValue = '' + val; + activeElementValueProp.set.call(this, val); + } +}; + +/** + * (For old IE.) Starts tracking propertychange events on the passed-in element + * and override the value property so that we can distinguish user events from + * value changes in JS. + */ +function startWatchingForValueChange(target, targetID) { + activeElement = target; + activeElementID = targetID; + activeElementValue = target.value; + activeElementValueProp = Object.getOwnPropertyDescriptor( + target.constructor.prototype, + 'value' + ); + + Object.defineProperty(activeElement, 'value', newValueProp); + activeElement.attachEvent('onpropertychange', handlePropertyChange); +} + +/** + * (For old IE.) Removes the event listeners from the currently-tracked element, + * if any exists. + */ +function stopWatchingForValueChange() { + if (!activeElement) { + return; + } + + // delete restores the original property definition + delete activeElement.value; + activeElement.detachEvent('onpropertychange', handlePropertyChange); + + activeElement = null; + activeElementID = null; + activeElementValue = null; + activeElementValueProp = null; +} + +/** + * (For old IE.) Handles a propertychange event, sending a `change` event if + * the value of the active element has changed. + */ +function handlePropertyChange(nativeEvent) { + if (nativeEvent.propertyName !== 'value') { + return; + } + var value = nativeEvent.srcElement.value; + if (value === activeElementValue) { + return; + } + activeElementValue = value; + + manualDispatchChangeEvent(nativeEvent); +} + +/** + * If a `change` event should be fired, returns the target's ID. + */ +function getTargetIDForInputEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topInput) { + // In modern browsers (i.e., not IE8 or IE9), the input event is exactly + // what we want so fall through here and trigger an abstract event + return topLevelTargetID; + } +} + +// For IE8 and IE9. +function handleEventsForInputEventIE( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topFocus) { + // In IE8, we can capture almost all .value changes by adding a + // propertychange handler and looking for events with propertyName + // equal to 'value' + // In IE9, propertychange fires for most input events but is buggy and + // doesn't fire when text is deleted, but conveniently, selectionchange + // appears to fire in all of the remaining cases so we catch those and + // forward the event if the value has changed + // In either case, we don't want to call the event handler if the value + // is changed from JS so we redefine a setter for `.value` that updates + // our activeElementValue variable, allowing us to ignore those changes + // + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForValueChange(); + startWatchingForValueChange(topLevelTarget, topLevelTargetID); + } else if (topLevelType === topLevelTypes.topBlur) { + stopWatchingForValueChange(); + } +} + +// For IE8 and IE9. +function getTargetIDForInputEventIE( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topSelectionChange || + topLevelType === topLevelTypes.topKeyUp || + topLevelType === topLevelTypes.topKeyDown) { + // On the selectionchange event, the target is just document which isn't + // helpful for us so just check activeElement instead. + // + // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire + // propertychange on the first input event after setting `value` from a + // script and fires only keydown, keypress, keyup. Catching keyup usually + // gets it and catching keydown lets us fire an event for the first + // keystroke if user does a key repeat (it'll be a little delayed: right + // before the second keystroke). Other input methods (e.g., paste) seem to + // fire selectionchange normally. + if (activeElement && activeElement.value !== activeElementValue) { + activeElementValue = activeElement.value; + return activeElementID; + } + } +} + + +/** + * SECTION: handle `click` event + */ +function shouldUseClickEvent(elem) { + // Use the `click` event to detect changes to checkbox and radio inputs. + // This approach works across all browsers, whereas `change` does not fire + // until `blur` in IE8. + return ( + elem.nodeName === 'INPUT' && + (elem.type === 'checkbox' || elem.type === 'radio') + ); +} + +function getTargetIDForClickEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topClick) { + return topLevelTargetID; + } +} + +/** + * This plugin creates an `onChange` event that normalizes change events + * across form elements. This event fires at a time when it's possible to + * change the element's value without seeing a flicker. + * + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - select + */ +var ChangeEventPlugin = { + + eventTypes: eventTypes, + + /** + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + + var getTargetIDFunc, handleEventFunc; + if (shouldUseChangeEvent(topLevelTarget)) { + if (doesChangeEventBubble) { + getTargetIDFunc = getTargetIDForChangeEvent; + } else { + handleEventFunc = handleEventsForChangeEventIE8; + } + } else if (isTextInputElement(topLevelTarget)) { + if (isInputEventSupported) { + getTargetIDFunc = getTargetIDForInputEvent; + } else { + getTargetIDFunc = getTargetIDForInputEventIE; + handleEventFunc = handleEventsForInputEventIE; + } + } else if (shouldUseClickEvent(topLevelTarget)) { + getTargetIDFunc = getTargetIDForClickEvent; + } + + if (getTargetIDFunc) { + var targetID = getTargetIDFunc( + topLevelType, + topLevelTarget, + topLevelTargetID + ); + if (targetID) { + var event = SyntheticEvent.getPooled( + eventTypes.change, + targetID, + nativeEvent + ); + EventPropagators.accumulateTwoPhaseDispatches(event); + return event; + } + } + + if (handleEventFunc) { + handleEventFunc( + topLevelType, + topLevelTarget, + topLevelTargetID + ); + } + } + +}; + +module.exports = ChangeEventPlugin; + +},{"./EventConstants":15,"./EventPluginHub":17,"./EventPropagators":20,"./ExecutionEnvironment":21,"./SyntheticEvent":76,"./isEventSupported":110,"./isTextInputElement":112,"./keyOf":116}],7:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CompositionEventPlugin + * @typechecks static-only + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var ReactInputSelection = require("./ReactInputSelection"); +var SyntheticCompositionEvent = require("./SyntheticCompositionEvent"); + +var getTextContentAccessor = require("./getTextContentAccessor"); +var keyOf = require("./keyOf"); + +var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space +var START_KEYCODE = 229; + +var useCompositionEvent = ExecutionEnvironment.canUseDOM && + 'CompositionEvent' in window; +var topLevelTypes = EventConstants.topLevelTypes; +var currentComposition = null; + +// Events and their corresponding property names. +var eventTypes = { + compositionEnd: { + phasedRegistrationNames: { + bubbled: keyOf({onCompositionEnd: null}), + captured: keyOf({onCompositionEndCapture: null}) + } + }, + compositionStart: { + phasedRegistrationNames: { + bubbled: keyOf({onCompositionStart: null}), + captured: keyOf({onCompositionStartCapture: null}) + } + }, + compositionUpdate: { + phasedRegistrationNames: { + bubbled: keyOf({onCompositionUpdate: null}), + captured: keyOf({onCompositionUpdateCapture: null}) + } + } +}; + +/** + * Translate native top level events into event types. + * + * @param {string} topLevelType + * @return {object} + */ +function getCompositionEventType(topLevelType) { + switch (topLevelType) { + case topLevelTypes.topCompositionStart: + return eventTypes.compositionStart; + case topLevelTypes.topCompositionEnd: + return eventTypes.compositionEnd; + case topLevelTypes.topCompositionUpdate: + return eventTypes.compositionUpdate; + } +} + +/** + * Does our fallback best-guess model think this event signifies that + * composition has begun? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackStart(topLevelType, nativeEvent) { + return ( + topLevelType === topLevelTypes.topKeyDown && + nativeEvent.keyCode === START_KEYCODE + ); +} + +/** + * Does our fallback mode think that this event is the end of composition? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackEnd(topLevelType, nativeEvent) { + switch (topLevelType) { + case topLevelTypes.topKeyUp: + // Command keys insert or clear IME input. + return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1); + case topLevelTypes.topKeyDown: + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return (nativeEvent.keyCode !== START_KEYCODE); + case topLevelTypes.topKeyPress: + case topLevelTypes.topMouseDown: + case topLevelTypes.topBlur: + // Events are not possible without cancelling IME. + return true; + default: + return false; + } +} + +/** + * Helper class stores information about selection and document state + * so we can figure out what changed at a later date. + * + * @param {DOMEventTarget} root + */ +function FallbackCompositionState(root) { + this.root = root; + this.startSelection = ReactInputSelection.getSelection(root); + this.startValue = this.getText(); +} + +/** + * Get current text of input. + * + * @return {string} + */ +FallbackCompositionState.prototype.getText = function() { + return this.root.value || this.root[getTextContentAccessor()]; +}; + +/** + * Text that has changed since the start of composition. + * + * @return {string} + */ +FallbackCompositionState.prototype.getData = function() { + var endValue = this.getText(); + var prefixLength = this.startSelection.start; + var suffixLength = this.startValue.length - this.startSelection.end; + + return endValue.substr( + prefixLength, + endValue.length - suffixLength - prefixLength + ); +}; + +/** + * This plugin creates `onCompositionStart`, `onCompositionUpdate` and + * `onCompositionEnd` events on inputs, textareas and contentEditable + * nodes. + */ +var CompositionEventPlugin = { + + eventTypes: eventTypes, + + /** + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + + var eventType; + var data; + + if (useCompositionEvent) { + eventType = getCompositionEventType(topLevelType); + } else if (!currentComposition) { + if (isFallbackStart(topLevelType, nativeEvent)) { + eventType = eventTypes.start; + currentComposition = new FallbackCompositionState(topLevelTarget); + } + } else if (isFallbackEnd(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionEnd; + data = currentComposition.getData(); + currentComposition = null; + } + + if (eventType) { + var event = SyntheticCompositionEvent.getPooled( + eventType, + topLevelTargetID, + nativeEvent + ); + if (data) { + // Inject data generated from fallback path into the synthetic event. + // This matches the property of native CompositionEventInterface. + event.data = data; + } + EventPropagators.accumulateTwoPhaseDispatches(event); + return event; + } + } +}; + +module.exports = CompositionEventPlugin; + +},{"./EventConstants":15,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactInputSelection":50,"./SyntheticCompositionEvent":75,"./getTextContentAccessor":106,"./keyOf":116}],8:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMChildrenOperations + * @typechecks static-only + */ + +"use strict"; + +var Danger = require("./Danger"); +var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes"); + +var getTextContentAccessor = require("./getTextContentAccessor"); + +/** + * The DOM property to use when setting text content. + * + * @type {string} + * @private + */ +var textContentAccessor = getTextContentAccessor() || 'NA'; + +/** + * Inserts `childNode` as a child of `parentNode` at the `index`. + * + * @param {DOMElement} parentNode Parent node in which to insert. + * @param {DOMElement} childNode Child node to insert. + * @param {number} index Index at which to insert the child. + * @internal + */ +function insertChildAt(parentNode, childNode, index) { + var childNodes = parentNode.childNodes; + if (childNodes[index] === childNode) { + return; + } + // If `childNode` is already a child of `parentNode`, remove it so that + // computing `childNodes[index]` takes into account the removal. + if (childNode.parentNode === parentNode) { + parentNode.removeChild(childNode); + } + if (index >= childNodes.length) { + parentNode.appendChild(childNode); + } else { + parentNode.insertBefore(childNode, childNodes[index]); + } +} + +/** + * Operations for updating with DOM children. + */ +var DOMChildrenOperations = { + + dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + + /** + * Updates a component's children by processing a series of updates. The + * update configurations are each expected to have a `parentNode` property. + * + * @param {array} updates List of update configurations. + * @param {array} markupList List of markup strings. + * @internal + */ + processUpdates: function(updates, markupList) { + var update; + // Mapping from parent IDs to initial child orderings. + var initialChildren = null; + // List of children that will be moved or removed. + var updatedChildren = null; + + for (var i = 0; update = updates[i]; i++) { + if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING || + update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) { + var updatedIndex = update.fromIndex; + var updatedChild = update.parentNode.childNodes[updatedIndex]; + var parentID = update.parentID; + + initialChildren = initialChildren || {}; + initialChildren[parentID] = initialChildren[parentID] || []; + initialChildren[parentID][updatedIndex] = updatedChild; + + updatedChildren = updatedChildren || []; + updatedChildren.push(updatedChild); + } + } + + var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); + + // Remove updated children first so that `toIndex` is consistent. + if (updatedChildren) { + for (var j = 0; j < updatedChildren.length; j++) { + updatedChildren[j].parentNode.removeChild(updatedChildren[j]); + } + } + + for (var k = 0; update = updates[k]; k++) { + switch (update.type) { + case ReactMultiChildUpdateTypes.INSERT_MARKUP: + insertChildAt( + update.parentNode, + renderedMarkup[update.markupIndex], + update.toIndex + ); + break; + case ReactMultiChildUpdateTypes.MOVE_EXISTING: + insertChildAt( + update.parentNode, + initialChildren[update.parentID][update.fromIndex], + update.toIndex + ); + break; + case ReactMultiChildUpdateTypes.TEXT_CONTENT: + update.parentNode[textContentAccessor] = update.textContent; + break; + case ReactMultiChildUpdateTypes.REMOVE_NODE: + // Already removed by the for-loop above. + break; + } + } + } + +}; + +module.exports = DOMChildrenOperations; + +},{"./Danger":11,"./ReactMultiChildUpdateTypes":57,"./getTextContentAccessor":106}],9:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMProperty + * @typechecks static-only + */ + +/*jslint bitwise: true */ + +"use strict"; + +var invariant = require("./invariant"); + +var DOMPropertyInjection = { + /** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ + MUST_USE_ATTRIBUTE: 0x1, + MUST_USE_PROPERTY: 0x2, + HAS_SIDE_EFFECTS: 0x4, + HAS_BOOLEAN_VALUE: 0x8, + HAS_POSITIVE_NUMERIC_VALUE: 0x10, + + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: + * + * isCustomAttribute: function that given an attribute name will return true + * if it can be inserted into the DOM verbatim. Useful for data-* or aria-* + * attributes where it's impossible to enumerate all of the possible + * attribute names, + * + * Properties: object mapping DOM property name to one of the + * DOMPropertyInjection constants or null. If your attribute isn't in here, + * it won't get written to the DOM. + * + * DOMAttributeNames: object mapping React attribute name to the DOM + * attribute name. Attribute names not specified use the **lowercase** + * normalized name. + * + * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. + * Property names not specified use the normalized name. + * + * DOMMutationMethods: Properties that require special mutation methods. If + * `value` is undefined, the mutation method should unset the property. + * + * @param {object} domPropertyConfig the config as described above. + */ + injectDOMPropertyConfig: function(domPropertyConfig) { + var Properties = domPropertyConfig.Properties || {}; + var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; + var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {}; + var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; + + if (domPropertyConfig.isCustomAttribute) { + DOMProperty._isCustomAttributeFunctions.push( + domPropertyConfig.isCustomAttribute + ); + } + + for (var propName in Properties) { + ("production" !== "development" ? invariant( + !DOMProperty.isStandardName[propName], + 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' + + '\'%s\' which has already been injected. You may be accidentally ' + + 'injecting the same DOM property config twice, or you may be ' + + 'injecting two configs that have conflicting property names.', + propName + ) : invariant(!DOMProperty.isStandardName[propName])); + + DOMProperty.isStandardName[propName] = true; + + var lowerCased = propName.toLowerCase(); + DOMProperty.getPossibleStandardName[lowerCased] = propName; + + var attributeName = DOMAttributeNames[propName]; + if (attributeName) { + DOMProperty.getPossibleStandardName[attributeName] = propName; + } + + DOMProperty.getAttributeName[propName] = attributeName || lowerCased; + + DOMProperty.getPropertyName[propName] = + DOMPropertyNames[propName] || propName; + + var mutationMethod = DOMMutationMethods[propName]; + if (mutationMethod) { + DOMProperty.getMutationMethod[propName] = mutationMethod; + } + + var propConfig = Properties[propName]; + DOMProperty.mustUseAttribute[propName] = + propConfig & DOMPropertyInjection.MUST_USE_ATTRIBUTE; + DOMProperty.mustUseProperty[propName] = + propConfig & DOMPropertyInjection.MUST_USE_PROPERTY; + DOMProperty.hasSideEffects[propName] = + propConfig & DOMPropertyInjection.HAS_SIDE_EFFECTS; + DOMProperty.hasBooleanValue[propName] = + propConfig & DOMPropertyInjection.HAS_BOOLEAN_VALUE; + DOMProperty.hasPositiveNumericValue[propName] = + propConfig & DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE; + + ("production" !== "development" ? invariant( + !DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName], + 'DOMProperty: Cannot require using both attribute and property: %s', + propName + ) : invariant(!DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName])); + ("production" !== "development" ? invariant( + DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName], + 'DOMProperty: Properties that have side effects must use property: %s', + propName + ) : invariant(DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName])); + ("production" !== "development" ? invariant( + !DOMProperty.hasBooleanValue[propName] || + !DOMProperty.hasPositiveNumericValue[propName], + 'DOMProperty: Cannot have both boolean and positive numeric value: %s', + propName + ) : invariant(!DOMProperty.hasBooleanValue[propName] || + !DOMProperty.hasPositiveNumericValue[propName])); + } + } +}; +var defaultValueCache = {}; + +/** + * DOMProperty exports lookup objects that can be used like functions: + * + * > DOMProperty.isValid['id'] + * true + * > DOMProperty.isValid['foobar'] + * undefined + * + * Although this may be confusing, it performs better in general. + * + * @see http://jsperf.com/key-exists + * @see http://jsperf.com/key-missing + */ +var DOMProperty = { + + /** + * Checks whether a property name is a standard property. + * @type {Object} + */ + isStandardName: {}, + + /** + * Mapping from lowercase property names to the properly cased version, used + * to warn in the case of missing properties. + * @type {Object} + */ + getPossibleStandardName: {}, + + /** + * Mapping from normalized names to attribute names that differ. Attribute + * names are used when rendering markup or with `*Attribute()`. + * @type {Object} + */ + getAttributeName: {}, + + /** + * Mapping from normalized names to properties on DOM node instances. + * (This includes properties that mutate due to external factors.) + * @type {Object} + */ + getPropertyName: {}, + + /** + * Mapping from normalized names to mutation methods. This will only exist if + * mutation cannot be set simply by the property or `setAttribute()`. + * @type {Object} + */ + getMutationMethod: {}, + + /** + * Whether the property must be accessed and mutated as an object property. + * @type {Object} + */ + mustUseAttribute: {}, + + /** + * Whether the property must be accessed and mutated using `*Attribute()`. + * (This includes anything that fails ` in `.) + * @type {Object} + */ + mustUseProperty: {}, + + /** + * Whether or not setting a value causes side effects such as triggering + * resources to be loaded or text selection changes. We must ensure that + * the value is only set if it has changed. + * @type {Object} + */ + hasSideEffects: {}, + + /** + * Whether the property should be removed when set to a falsey value. + * @type {Object} + */ + hasBooleanValue: {}, + + /** + * Whether the property must be positive numeric or parse as a positive + * numeric and should be removed when set to a falsey value. + * @type {Object} + */ + hasPositiveNumericValue: {}, + + /** + * All of the isCustomAttribute() functions that have been injected. + */ + _isCustomAttributeFunctions: [], + + /** + * Checks whether a property name is a custom attribute. + * @method + */ + isCustomAttribute: function(attributeName) { + return DOMProperty._isCustomAttributeFunctions.some( + function(isCustomAttributeFn) { + return isCustomAttributeFn.call(null, attributeName); + } + ); + }, + + /** + * Returns the default property value for a DOM property (i.e., not an + * attribute). Most default values are '' or false, but not all. Worse yet, + * some (in particular, `type`) vary depending on the type of element. + * + * TODO: Is it better to grab all the possible properties when creating an + * element to avoid having to create the same element twice? + */ + getDefaultValueForProperty: function(nodeName, prop) { + var nodeDefaults = defaultValueCache[nodeName]; + var testElement; + if (!nodeDefaults) { + defaultValueCache[nodeName] = nodeDefaults = {}; + } + if (!(prop in nodeDefaults)) { + testElement = document.createElement(nodeName); + nodeDefaults[prop] = testElement[prop]; + } + return nodeDefaults[prop]; + }, + + injection: DOMPropertyInjection +}; + +module.exports = DOMProperty; + +},{"./invariant":109}],10:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMPropertyOperations + * @typechecks static-only + */ + +"use strict"; + +var DOMProperty = require("./DOMProperty"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +function shouldIgnoreValue(name, value) { + return value == null || + DOMProperty.hasBooleanValue[name] && !value || + DOMProperty.hasPositiveNumericValue[name] && (isNaN(value) || value < 1); +} + +var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { + return escapeTextForBrowser(name) + '="'; +}); + +if ("production" !== "development") { + var reactProps = { + __owner__: true, + children: true, + dangerouslySetInnerHTML: true, + key: true, + ref: true + }; + var warnedProperties = {}; + + var warnUnknownProperty = function(name) { + if (reactProps[name] || warnedProperties[name]) { + return; + } + + warnedProperties[name] = true; + var lowerCasedName = name.toLowerCase(); + + // data-* attributes should be lowercase; suggest the lowercase version + var standardName = DOMProperty.isCustomAttribute(lowerCasedName) ? + lowerCasedName : DOMProperty.getPossibleStandardName[lowerCasedName]; + + // For now, only warn when we have a suggested correction. This prevents + // logging too much when using transferPropsTo. + if (standardName != null) { + console.warn( + 'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?' + ); + } + + }; +} + +/** + * Operations for dealing with DOM properties. + */ +var DOMPropertyOperations = { + + /** + * Creates markup for a property. + * + * @param {string} name + * @param {*} value + * @return {?string} Markup string, or null if the property was invalid. + */ + createMarkupForProperty: function(name, value) { + if (DOMProperty.isStandardName[name]) { + if (shouldIgnoreValue(name, value)) { + return ''; + } + var attributeName = DOMProperty.getAttributeName[name]; + return processAttributeNameAndPrefix(attributeName) + + escapeTextForBrowser(value) + '"'; + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + return ''; + } + return processAttributeNameAndPrefix(name) + + escapeTextForBrowser(value) + '"'; + } else if ("production" !== "development") { + warnUnknownProperty(name); + } + return null; + }, + + /** + * Sets the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + * @param {*} value + */ + setValueForProperty: function(node, name, value) { + if (DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, value); + } else if (shouldIgnoreValue(name, value)) { + this.deleteValueForProperty(node, name); + } else if (DOMProperty.mustUseAttribute[name]) { + node.setAttribute(DOMProperty.getAttributeName[name], '' + value); + } else { + var propName = DOMProperty.getPropertyName[name]; + if (!DOMProperty.hasSideEffects[name] || node[propName] !== value) { + node[propName] = value; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + node.setAttribute(name, '' + value); + } + } else if ("production" !== "development") { + warnUnknownProperty(name); + } + }, + + /** + * Deletes the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + */ + deleteValueForProperty: function(node, name) { + if (DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, undefined); + } else if (DOMProperty.mustUseAttribute[name]) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + var propName = DOMProperty.getPropertyName[name]; + var defaultValue = DOMProperty.getDefaultValueForProperty( + node.nodeName, + name + ); + if (!DOMProperty.hasSideEffects[name] || + node[propName] !== defaultValue) { + node[propName] = defaultValue; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.removeAttribute(name); + } else if ("production" !== "development") { + warnUnknownProperty(name); + } + } + +}; + +module.exports = DOMPropertyOperations; + +},{"./DOMProperty":9,"./escapeTextForBrowser":95,"./memoizeStringOnly":117}],11:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule Danger + * @typechecks static-only + */ + +/*jslint evil: true, sub: true */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var createNodesFromMarkup = require("./createNodesFromMarkup"); +var emptyFunction = require("./emptyFunction"); +var getMarkupWrap = require("./getMarkupWrap"); +var invariant = require("./invariant"); +var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup"); + +var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/; +var RESULT_INDEX_ATTR = 'data-danger-index'; + +/** + * Extracts the `nodeName` from a string of markup. + * + * NOTE: Extracting the `nodeName` does not require a regular expression match + * because we make assumptions about React-generated markup (i.e. there are no + * spaces surrounding the opening tag and there is at least one attribute). + * + * @param {string} markup String of markup. + * @return {string} Node name of the supplied markup. + * @see http://jsperf.com/extract-nodename + */ +function getNodeName(markup) { + return markup.substring(1, markup.indexOf(' ')); +} + +var Danger = { + + /** + * Renders markup into an array of nodes. The markup is expected to render + * into a list of root nodes. Also, the length of `resultList` and + * `markupList` should be the same. + * + * @param {array} markupList List of markup strings to render. + * @return {array} List of rendered nodes. + * @internal + */ + dangerouslyRenderMarkup: function(markupList) { + ("production" !== "development" ? invariant( + ExecutionEnvironment.canUseDOM, + 'dangerouslyRenderMarkup(...): Cannot render markup in a Worker ' + + 'thread. This is likely a bug in the framework. Please report ' + + 'immediately.' + ) : invariant(ExecutionEnvironment.canUseDOM)); + var nodeName; + var markupByNodeName = {}; + // Group markup by `nodeName` if a wrap is necessary, else by '*'. + for (var i = 0; i < markupList.length; i++) { + ("production" !== "development" ? invariant( + markupList[i], + 'dangerouslyRenderMarkup(...): Missing markup.' + ) : invariant(markupList[i])); + nodeName = getNodeName(markupList[i]); + nodeName = getMarkupWrap(nodeName) ? nodeName : '*'; + markupByNodeName[nodeName] = markupByNodeName[nodeName] || []; + markupByNodeName[nodeName][i] = markupList[i]; + } + var resultList = []; + var resultListAssignmentCount = 0; + for (nodeName in markupByNodeName) { + if (!markupByNodeName.hasOwnProperty(nodeName)) { + continue; + } + var markupListByNodeName = markupByNodeName[nodeName]; + + // This for-in loop skips the holes of the sparse array. The order of + // iteration should follow the order of assignment, which happens to match + // numerical index order, but we don't rely on that. + for (var resultIndex in markupListByNodeName) { + if (markupListByNodeName.hasOwnProperty(resultIndex)) { + var markup = markupListByNodeName[resultIndex]; + + // Push the requested markup with an additional RESULT_INDEX_ATTR + // attribute. If the markup does not start with a < character, it + // will be discarded below (with an appropriate console.error). + markupListByNodeName[resultIndex] = markup.replace( + OPEN_TAG_NAME_EXP, + // This index will be parsed back out below. + '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" ' + ); + } + } + + // Render each group of markup with similar wrapping `nodeName`. + var renderNodes = createNodesFromMarkup( + markupListByNodeName.join(''), + emptyFunction // Do nothing special with