diff --git a/labs/architecture-examples/react/bower.json b/labs/architecture-examples/react/bower.json index 2c4a5f17f6..c5a637a220 100644 --- a/labs/architecture-examples/react/bower.json +++ b/labs/architecture-examples/react/bower.json @@ -3,6 +3,6 @@ "version": "0.0.0", "dependencies": { "todomvc-common": "~0.1.7", - "react": "~0.3.2" + "react": "~0.4.0" } } diff --git a/labs/architecture-examples/react/bower_components/react/.bower.json b/labs/architecture-examples/react/bower_components/react/.bower.json new file mode 100644 index 0000000000..eee7876526 --- /dev/null +++ b/labs/architecture-examples/react/bower_components/react/.bower.json @@ -0,0 +1,14 @@ +{ + "name": "react", + "version": "0.4.0", + "main": "react.js", + "homepage": "https://github.com/facebook/react-bower", + "_release": "0.4.0", + "_resolution": { + "type": "version", + "tag": "v0.4.0", + "commit": "54334ad626d26dff4c214d308cefd30ad80fb8e9" + }, + "_source": "git://github.com/facebook/react-bower.git", + "_target": "~0.4.0" +} \ No newline at end of file diff --git a/labs/architecture-examples/react/bower_components/react/JSXTransformer.js b/labs/architecture-examples/react/bower_components/react/JSXTransformer.js index 147a66d835..2e4d7b5265 100644 --- a/labs/architecture-examples/react/bower_components/react/JSXTransformer.js +++ b/labs/architecture-examples/react/bower_components/react/JSXTransformer.js @@ -1,753 +1,286 @@ /** - * JSXTransformer v0.3.2 + * JSXTransformer v0.4.0 */ (function(e){if("function"==typeof bootstrap)bootstrap("jsxtransformer",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeJSXTransformer=e}else"undefined"!=typeof window?window.JSXTransformer=e():global.JSXTransformer=e()})(function(){var define,ses,bootstrap,module,exports; return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s 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 + }; - window.moduleLoads = (window.moduleLoads || []).concat(moduleName); - window.startTime = Date.now(); - var functionBody = jsx ? transform(code).code : code; - Function('require', 'module', 'exports', functionBody)(require, module, exports); - window.endTime = Date.now(); - require[moduleName] = module.exports; -}; + return my; +}({})); -if (typeof window === "undefined" || window === null) { - return; +module.exports = Base62 +},{}],2:[function(require,module,exports){ +(function(process){function filter (xs, fn) { + var res = []; + for (var i = 0; i < xs.length; i++) { + if (fn(xs[i], i, xs)) res.push(xs[i]); + } + return res; } -var load = exports.load = function(url, callback) { - var xhr; - xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(); - xhr.open('GET', url, false); - if ('overrideMimeType' in xhr) { - xhr.overrideMimeType('text/plain'); - } - xhr.onreadystatechange = function() { - var _ref; - if (xhr.readyState === 4) { - if ((_ref = xhr.status) === 0 || _ref === 200) { - run(xhr.responseText); - } else { - throw new Error("Could not load " + url); - } - if (callback) { - return callback(); - } +// 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; 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--; } - }; - return xhr.send(null); -}; + } -runScripts = function() { - var jsxes, execute, index, length, s, scripts; - scripts = document.getElementsByTagName('script'); - jsxes = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = scripts.length; _i < _len; _i++) { - s = scripts[_i]; - if (s.type === 'text/jsx') { - _results.push(s); - } - } - return _results; - })(); - index = 0; - length = jsxes.length; - (execute = function(j) { - var script; - script = jsxes[j]; - if ((script != null ? script.type : void 0) === 'text/jsx') { - if (script.src) { - return load(script.src, execute); - } else { - run(script.innerHTML); - return execute(); - } + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); } - }); - for (var i = 0; i < jsxes.length; i++) { - execute(i); } - return null; -}; - -if (window.addEventListener) { - window.addEventListener('DOMContentLoaded', runScripts, false); -} else { - window.attachEvent('onload', runScripts); -} - -},{"./fbtransform/lib/transform":2,"./fbtransform/visitors":3,"./fbtransform/lib/docblock":4}],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. - */ -var docblockRe = /^\s*(\/\*\*(.|\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 ''; + return parts; } +// Regex to split a filename into [*, dir, basename, ext] +// posix version +var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/; -var commentStartRe = /^\/\*\*?/; -var commentEndRe = /\*\/$/; -var wsRe = /[\t ]+/g; -var stringStartRe = /(\n|^) *\*/g; -var multilineRe = /(?:^|\n) *(@[^\n]*?) *\n *([^@\n\s][^@\n]+?) *\n/g; -var propertyRe = /(?:^|\n) *@(\S+) *([^\n]*)/g; - -/** - * @param {String} contents - * @return {Array} - */ -function parse(docblock) { - docblock = docblock - .replace(commentStartRe, '') - .replace(commentEndRe, '') - .replace(wsRe, ' ') - .replace(stringStartRe, '$1'); +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { +var resolvedPath = '', + resolvedAbsolute = false; - // Normalize multi-line directives - var prev = ''; - while (prev != docblock) { - prev = docblock; - docblock = docblock.replace(multilineRe, "\n$1 $2\n"); - } - docblock = docblock.trim(); +for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) + ? arguments[i] + : process.cwd(); - var result = []; - var match; - while (match = propertyRe.exec(docblock)) { - result.push([match[1], match[2]]); + // Skip empty and invalid entries + if (typeof path !== 'string' || !path) { + continue; } - return result; + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; } -/** - * 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; -} +// 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(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); -exports.extract = extract; -exports.parse = parse; -exports.parseAsObject = parseAsObject; + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; -},{}],3:[function(require,module,exports){ -(function(){/*global exports:true*/ -var classes = require('./transforms/classes'); -var react = require('./transforms/react'); -var reactDisplayName = require('./transforms/reactDisplayName'); +// path.normalize(path) +// posix version +exports.normalize = function(path) { +var isAbsolute = path.charAt(0) === '/', + trailingSlash = path.slice(-1) === '/'; -/** - * Map from transformName => orderedListOfVisitors. - */ -var transformVisitors = { - 'es6-classes': [ - classes.visitClassExpression, - classes.visitClassDeclaration, - classes.visitSuperCall, - classes.visitPrivateProperty - ] +// Normalize the path +path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; }; -transformVisitors.react = transformVisitors[ - "es6-classes" -].concat([ - react.visitReactTag, - reactDisplayName.visitReactDisplayName -]); -/** - * Specifies the order in which each transform should run. - */ -var transformRunOrder = [ - 'es6-classes', - 'react' -]; +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + return p && typeof p === 'string'; + }).join('/')); +}; -/** - * 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]]); - } + +exports.dirname = function(path) { + var dir = splitPathRe.exec(path)[1] || ''; + var isWindows = false; + if (!dir) { + // No dirname + return '.'; + } else if (dir.length === 1 || + (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) { + // It is just a slash or a drive letter with a slash + return dir; + } else { + // It is a full dirname, strip trailing slash + return dir.substring(0, dir.length - 1); } - return ret; -} +}; -exports.getVisitorsList = getVisitorsList; -exports.transformVisitors = transformVisitors; -})() -},{"./transforms/classes":5,"./transforms/react":6,"./transforms/reactDisplayName":7}],8:[function(require,module,exports){ -(function(){/** - * 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*/ +exports.basename = function(path, ext) { + var f = splitPathRe.exec(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; +}; -/** - * State represents the given parser state. It has a 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, transformOptions) { - return { - /** - * Name of the super class variable - * @type {String} - */ - superVar: '', - /** - * Name of the enclosing class scope - * @type {String} - */ - scopeName: '', - /** - * 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, +exports.extname = function(path) { + return splitPathRe.exec(path)[3] || ''; +}; - /** - * Whether the thing was used - * @type {Boolean} - */ - tagNamespaceUsed: false, +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); - /** - * If using bolt xjs transformation - * @type {Boolean} - */ - isBolt: undefined, + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } - /** - * Whether to record source map (expensive) or not - * @type {SourceMapGenerator|null} - */ - sourceMap: null, + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } - /** - * Filename of the file being processed. Will be returned as a source - * attribute in the source map - */ - sourceMapFilename: 'source.js', + if (start > end) return []; + return arr.slice(start, end - start + 1); + } - /** - * Only when source map is used: last line in the source for which - * source map was generated - * @type {Number} - */ - sourceLine: 1, + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); - /** - * Only when source map is used: last line in the buffer for which - * source map was generated - * @type {Number} - */ - bufferLine: 1, + 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; + } + } - /** - * The top-level Program AST for the original file. - */ - originalProgramAST: null, + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } - sourceColumn: 0, - bufferColumn: 0 - } - }; -} + outputParts = outputParts.concat(toParts.slice(samePartsLength)); -/** - * 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) { - return { - g: state.g, - superVar: update.superVar || state.superVar, - scopeName: update.scopeName || state.scopeName - }; -} + return outputParts.join('/'); +}; -/** - * 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 - }); +})(require("__browserify_process")) +},{"__browserify_process":3}],3:[function(require,module,exports){ +// shim for using process in browser - // 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; -} +var process = module.exports = {}; -/** - * Applies `catchup` but passing in a function that removes any non-whitespace - * characters. - */ -var re = /(\S)/g; -function stripNonWhite(value) { - return value.replace(re, function() { - return ''; - }); -} -/** - * Catches up as `catchup` but turns each non-white character into a space. - */ -function catchupWhiteSpace(end, state) { - catchup(end, state, stripNonWhite); -} +process.nextTick = (function () { + var canSetImmediate = typeof window !== 'undefined' + && window.setImmediate; + var canPost = typeof window !== 'undefined' + && window.postMessage && window.addEventListener + ; -/** - * 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; + if (canSetImmediate) { + return function (f) { return window.setImmediate(f) }; } - 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; -} + 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); -/** - * Appends a string of text to the buffer - * @param {String} string - * @param {Object} state - */ -function append(string, state) { - if (state.g.sourceMap && string) { - 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 = string.split('\n'); - if (transformedLines.length > 1) { - state.g.bufferLine += transformedLines.length - 1; - state.g.bufferColumn = 0; + return function nextTick(fn) { + queue.push(fn); + window.postMessage('process-tick', '*'); + }; } - state.g.bufferColumn += - transformedLines[transformedLines.length - 1].length; - } - state.g.buffer += string; -} - -/** - * 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; + return function nextTick(fn) { + setTimeout(fn, 0); + }; +})(); - 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); -} +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; -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; +process.binding = function (name) { + throw new Error('process.binding is not supported'); } -exports.catchup = catchup; -exports.catchupWhiteSpace = catchupWhiteSpace; -exports.append = append; -exports.move = move; -exports.updateIndent = updateIndent; -exports.indentBefore = indentBefore; -exports.updateState = updateState; -exports.createState = createState; -exports.getDocblock = getDocblock; +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; -})() -},{"./docblock":4}],2:[function(require,module,exports){ -(function(){/** - * 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*/ -/*jslint node: true*/ -"use strict"; +},{}],4:[function(require,module,exports){ +(function(){/* + 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 -/** - * Syntax transfomer for javascript. Takes the source in, spits the source - * out. Tries to maintain readability and preserve whitespace and line numbers - * where posssible. - * - * Support - * - ES6 class transformation + private property munging, see ./classes.js - * - React XHP style syntax transformations, see ./react.js - * - Bolt XHP style syntax transformations, see ./bolt.js - * - * The general flow is the following: - * - Parse the source with our customized esprima-parser - * https://github.com/voloko/esprima. We have to customize the parser to - * support non-standard XHP-style syntax. We parse the source range: true - * option that forces esprima to return positions in the source within - * resulting parse tree. - * - * - Traverse resulting syntax tree, trying to apply a set of visitors to each - * node. Each visitor should provide a .test() function that tests if the - * visitor can process a given node. - * - * - Visitor is responsible for code generation for a given syntax node. - * Generated code is stored in state.g.buffer that is passed to every - * visitor. It's up to the visitor to process the code the way it sees fit. - * All of the current visitors however use both the node and the original - * source to generate transformed code. They use nodes to generate new - * code and they copy the original source, preserving whitespace and comments, - * for the parts they don't care about. - */ -var esprima = require('esprima'); + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: -var createState = require('./utils').createState; -var catchup = require('./utils').catchup; - -/** - * @param {object} object - * @param {function} visitor - * @param {array} path - * @param {object} state - */ -function traverse(object, path, state) { - var key, child; - - if (walker(traverse, object, path, state) === false) { - return; - } - path.unshift(object); - for (key in object) { - // skip obviously wrong attributes - if (key === 'range' || key === 'loc') { - continue; - } - if (object.hasOwnProperty(key)) { - child = object[key]; - if (typeof child === 'object' && child !== null) { - child.range && catchup(child.range[0], state); - traverse(child, path, state); - child.range && catchup(child.range[1], state); - } - } - } - path.shift(); -} - -function walker(traverse, object, path, state) { - var visitors = state.g.visitors; - for (var i = 0; i < visitors.length; i++) { - if (visitors[i].test(object, path, state)) { - return visitors[i](traverse, object, path, state); - } - } -} - -function runPass(source, visitors, options) { - var ast = esprima.parse(source, { comment: true, loc: true, range: true }); - var state = createState(source, options); - state.g.originalProgramAST = ast; - 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); - return 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 state = runPass(source, visitors, options); - var sourceMap = state.g.sourceMap; - - if (sourceMap) { - return { - sourceMap: sourceMap, - sourceMapFilename: options.filename || 'source.js', - code: state.g.buffer - }; - } else { - return { - code: state.g.buffer - }; - } -} - - -exports.transform = transform; - -})() -},{"./utils":8,"esprima":9,"source-map":10}],9:[function(require,module,exports){ -(function(){/* - 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. + * 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 @@ -775,7 +308,7 @@ 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, parseXJSExpression: true, +parseXJSAttributeValue: true, parseXJSChild: true, parseXJSElement: true, parseXJSExpressionContainer: true, parseXJSEmptyExpression: true, parseYieldExpression: true */ @@ -919,7 +452,8 @@ parseYieldExpression: true WhileStatement: 'WhileStatement', WithStatement: 'WithStatement', XJSIdentifier: 'XJSIdentifier', - XJSExpression: 'XJSExpression', + XJSEmptyExpression: 'XJSEmptyExpression', + XJSExpressionContainer: 'XJSExpressionContainer', XJSElement: 'XJSElement', XJSClosingElement: 'XJSClosingElement', XJSOpeningElement: 'XJSOpeningElement', @@ -935,8 +469,8 @@ parseYieldExpression: true }; ClassPropertyType = { - static: 1, - prototype: 2 + static: 'static', + prototype: 'prototype' }; // Error messages should be identical to V8. @@ -2472,10 +2006,16 @@ parseYieldExpression: true }; }, - createXJSExpression: function (expression) { + createXJSEmptyExpression: function () { return { - type: Syntax.XJSExpression, - value: expression + type: Syntax.XJSEmptyExpression + }; + }, + + createXJSExpressionContainer: function (expression) { + return { + type: Syntax.XJSExpressionContainer, + expression: expression }; }, @@ -5105,7 +4645,7 @@ parseYieldExpression: true function parseMethodDefinition(existingPropNames) { var token, key, param, propType, isValidDuplicateProp = false; - if (strict ? matchKeyword('static') : matchContextualKeyword('static')) { + if (lookahead.value === 'static') { propType = ClassPropertyType.static; lex(); } else { @@ -5911,6 +5451,7 @@ parseYieldExpression: true ch = source[index++]; if (isLineTerminator(ch.charCodeAt(0))) { ++lineNumber; + lineStart = index; } str += ch; } @@ -5975,8 +5516,15 @@ parseYieldExpression: true function parseXJSAttributeValue() { var value; - if (lookahead.value === '{') { - value = parseXJSExpression(); + 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 { @@ -5985,8 +5533,15 @@ parseYieldExpression: true return value; } - function parseXJSExpression() { - var value, origInXJSChild, origInXJSTag; + function parseXJSEmptyExpression() { + while (source.charAt(index) !== '}') { + index++; + } + return delegate.createXJSEmptyExpression(); + } + + function parseXJSExpressionContainer() { + var expression, origInXJSChild, origInXJSTag; origInXJSChild = state.inXJSChild; origInXJSTag = state.inXJSTag; @@ -5995,14 +5550,18 @@ parseYieldExpression: true expect('{'); - value = parseExpression(); + if (match('}')) { + expression = parseXJSEmptyExpression(); + } else { + expression = parseExpression(); + } state.inXJSChild = origInXJSChild; state.inXJSTag = origInXJSTag; expect('}'); - return delegate.createXJSExpression(value); + return delegate.createXJSExpressionContainer(expression); } function parseXJSAttribute() { @@ -6021,8 +5580,8 @@ parseYieldExpression: true function parseXJSChild() { var token; - if (lookahead.value === '{') { - token = parseXJSExpression(); + if (match('{')) { + token = parseXJSExpressionContainer(); } else if (lookahead.type === Token.XJSText) { token = delegate.createLiteral(lex()); } else { @@ -6236,6 +5795,11 @@ parseYieldExpression: true }; marker.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]]; } @@ -6503,7 +6067,8 @@ parseYieldExpression: true extra.parseXJSChild = parseXJSChild; extra.parseXJSAttribute = parseXJSAttribute; extra.parseXJSAttributeValue = parseXJSAttributeValue; - extra.parseXJSExpression = parseXJSExpression; + extra.parseXJSExpressionContainer = parseXJSExpressionContainer; + extra.parseXJSEmptyExpression = parseXJSEmptyExpression; extra.parseXJSElement = parseXJSElement; extra.parseXJSClosingElement = parseXJSClosingElement; extra.parseXJSOpeningElement = parseXJSOpeningElement; @@ -6555,7 +6120,8 @@ parseYieldExpression: true parseXJSChild = wrapTrackingPreserveWhitespace(extra.parseXJSChild); parseXJSAttribute = wrapTracking(extra.parseXJSAttribute); parseXJSAttributeValue = wrapTracking(extra.parseXJSAttributeValue); - parseXJSExpression = wrapTracking(extra.parseXJSExpression); + parseXJSExpressionContainer = wrapTracking(extra.parseXJSExpressionContainer); + parseXJSEmptyExpression = wrapTrackingPreserveWhitespace(extra.parseXJSEmptyExpression); parseXJSElement = wrapTracking(extra.parseXJSElement); parseXJSClosingElement = wrapTracking(extra.parseXJSClosingElement); parseXJSOpeningElement = wrapTracking(extra.parseXJSOpeningElement); @@ -6624,7 +6190,8 @@ parseYieldExpression: true parseXJSChild = extra.parseXJSChild; parseXJSAttribute = extra.parseXJSAttribute; parseXJSAttributeValue = extra.parseXJSAttributeValue; - parseXJSExpression = extra.parseXJSExpression; + parseXJSExpressionContainer = extra.parseXJSExpressionContainer; + parseXJSEmptyExpression = extra.parseXJSEmptyExpression; parseXJSElement = extra.parseXJSElement; parseXJSClosingElement = extra.parseXJSClosingElement; parseXJSOpeningElement = extra.parseXJSOpeningElement; @@ -6879,1094 +6446,1214 @@ parseYieldExpression: true /* vim: set sw=4 ts=4 et tw=80 : */ })() -},{}],11:[function(require,module,exports){ -(function(){/** - * Copyright 2013 Facebook, Inc. +},{}],5:[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":10,"./source-map/source-map-generator":11,"./source-map/source-node":12}],6:[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, require); +} +define(function (require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i]); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String 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[util.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, + util.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[util.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; + +}); + +},{"./util":13,"amdefine":14}],7:[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 * - * 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 + * 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 * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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: * - * 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 catchup = require('../lib/utils').catchup; -var append = require('../lib/utils').append; -var move = require('../lib/utils').move; - -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, - blockquote: true, - body: true, - br: true, - button: true, - canvas: true, - circle: true, - ellipse: true, - caption: 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, - 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, - map: true, - mark: true, - marquee: true, - menu: true, - meta: true, - meter: true, - nav: true, - noscript: true, - object: true, - ol: true, - optgroup: true, - option: true, - output: true, - p: true, - path: true, - param: 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: + * * 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. * - * "line "+ - * "line" + * 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. */ -function renderXJSLiteral(object, isLast, state, start, end) { - /** Added blank check filtering and triming*/ - var trimmedChildValue = safeTrim(object.value); - - if (trimmedChildValue) { - // head whitespace - append(object.value.match(/^[\t ]*/)[0], state); - if (start) { - append(start, state); - } - - var trimmedChildValueWithSpace = trimWithSingleSpace(object.value); +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { - /** - */ - var initialLines = trimmedChildValue.split(/\r\n|\n|\r/); + var base64 = require('./base64'); - var lines = initialLines.filter(function(line) { - return safeTrim(line).length > 0; - }); + // 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 hasInitialNewLine = initialLines[0] !== lines[0]; - var hasFinalNewLine = - initialLines[initialLines.length - 1] !== lines[lines.length - 1]; + var VLQ_BASE_SHIFT = 5; - 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 = ''; + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - if (ii === 0) { - if (hasInitialNewLine) { - preString = ' '; - leading = '\n'; - } - 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 = ' '; - } - } else { - leading = line.match(/^[ \t]*/)[0]; - } - 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 = ' '; - } + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; - 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); - } + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; - // add comma before trailing whitespace - if (!isLast) { - append(',', state); + /** + * 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; } - // tail whitespace - append(object.value.match(/[ \t]*$/)[0], state); - move(object.range[1], state); -} - -function renderXJSExpression(traverse, object, isLast, path, state) { - // Plus 1 to skip `{`. - move(object.range[0] + 1, state); - traverse(object.value, path, state); - if (!isLast) { - // If we need to append a comma, make sure to do so after the expression. - catchup(object.value.range[1], state); - append(',', state); + /** + * 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; } - // 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; -} + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; -exports.knownTags = knownTags; -exports.renderXJSExpression = renderXJSExpression; -exports.renderXJSLiteral = renderXJSLiteral; -exports.quoteAttrName = quoteAttrName; + var vlq = toVLQSigned(aValue); -})() -},{"../lib/utils":8}],10:[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; + 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); -},{"./source-map/source-map-generator":12,"./source-map/source-map-consumer":13,"./source-map/source-node":14}],5:[function(require,module,exports){ -(function(){/** - * 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"; + return encoded; + }; -/** - * Desugarizer for ES6 minimal class proposal. See - * http://wiki.ecmascript.org/doku.php?id=harmony:proposals - * - * Does not require any runtime. Preserves whitespace and comments. - * Supports a class declaration with methods, super calls and inheritance. - * Currently does not support for getters and setters, since there's a very - * low probability we're going to use them anytime soon. - * - * Additional features: - * - Any member with private name (the name with prefix _, such _name) inside - * the class's scope will be munged. This would will to eliminate the case - * of sub-class accidentally overriding the super-class's provate properties - * also discouage people from accessing private members that they should not - * access. However, quoted property names don't get munged. - * - * class SkinnedMesh extends require('THREE').Mesh { - * - * update(camera) { - * camera.code = 'iphone' - * super.update(camera); - * } - * - * / - * * @constructor - * / - * constructor(geometry, materials) { - * super(geometry, materials); - * - * super.update(1); - * - * this.identityMatrix = new THREE.Matrix4(); - * this.bones = []; - * this.boneMatrices = []; - * this._name = 'foo'; - * } - * - * / - * * some other code - * / - * readMore() { - * - * } - * - * _doSomething() { - * - * } - * } - * - * should be converted to - * - * var SkinnedMesh = (function() { - * var __super = require('parent').Mesh; - * - * / - * * @constructor - * / - * function SkinnedMesh(geometry, materials) { - * __super.call(this, geometry, materials); - * - * __super.prototype.update.call(this, 1); - * - * this.identityMatrix = new THREE.Matrix4(); - * this.bones = []; - * this.boneMatrices = []; - * this.$SkinnedMesh_name = 'foo'; - * } - * SkinnedMesh.prototype = Object.create(__super.prototype); - * SkinnedMesh.prototype.constructor = SkinnedMesh; - * - * / - * * @param camera - * / - * SkinnedMesh.prototype.update = function(camera) { - * camera.code = 'iphone' - * __super.prototype.update.call(this, camera); - * }; - * - * SkinnedMesh.prototype.readMore = function() { - * - * }; - * - * SkinnedMesh.prototype.$SkinnedMesh_doSomething = function() { - * - * }; - * - * return SkinnedMesh; - * })(); - * - */ -var Syntax = require('esprima').Syntax; -var base62 = require('base62'); + /** + * 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; -var catchup = require('../lib/utils').catchup; -var append = require('../lib/utils').append; -var move = require('../lib/utils').move; -var indentBefore = require('../lib/utils').indentBefore; -var updateIndent = require('../lib/utils').updateIndent; -var updateState = require('../lib/utils').updateState; + 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); -function findConstructorIndex(object) { - var classElements = object.body && object.body.body || []; - for (var i = 0; i < classElements.length; i++) { - if (classElements[i].type === Syntax.MethodDefinition && - classElements[i].key.name === 'constructor') { - return i; - } - } - return -1; + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); + +},{"./base64":8,"amdefine":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, require); } +define(function (require, exports, module) { -var _mungedSymbolMaps = {}; -function getMungedName(scopeName, name, minify) { - if (minify) { - if (!_mungedSymbolMaps[scopeName]) { - _mungedSymbolMaps[scopeName] = { - symbolMap: {}, - identifierUUIDCounter: 0 - }; + 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); + }; - var symbolMap = _mungedSymbolMaps[scopeName].symbolMap; - if (!symbolMap[name]) { - symbolMap[name] = - base62.encode(_mungedSymbolMaps[scopeName].identifierUUIDCounter); - _mungedSymbolMaps[scopeName].identifierUUIDCounter++; + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; } - name = symbolMap[name]; - } - return '$' + scopeName + name; -} + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; -function shouldMungeName(scopeName, name, state) { - // only run when @preventMunge is not present in the docblock - if (state.g.preventMunge === undefined) { - var docblock = require('../lib/docblock'); - state.g.preventMunge = docblock.parseAsObject( - docblock.extract(state.g.source)).preventMunge !== undefined; - } - // Starts with only a single underscore (i.e. don't count double-underscores) - return !state.g.preventMunge && scopeName ? /^_(?!_)/.test(name) : false; +}); + +},{"amdefine":14}],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 + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); } +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]; + } + } -function getProtoOfPrototypeVariableName(superVar) { - return superVar + 'ProtoOfPrototype'; -} + /** + * 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; + }; -function getSuperKeyName(superVar) { - return superVar + 'Key'; -} +}); -function getSuperProtoOfPrototypeVariable(superVariableName, indent) { - var string = (indent + - 'var $proto = $superName && $superName.prototype ? ' + - '$superName.prototype : $superName;\n' - ).replace(/\$proto/g, getProtoOfPrototypeVariableName(superVariableName)) - .replace(/\$superName/g, superVariableName); - return string; +},{"amdefine":14}],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, require); } +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'); -function getInheritanceSetup(superClassToken, className, indent, superName) { - var string = ''; - if (superClassToken) { - string += getStaticMethodsOnConstructorSetup(className, indent, superName); - string += getPrototypeOnConstructorSetup(className, indent, superName); - string += getConstructorPropertySetup(className, indent); - } - return string; -} + /** + * 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. + * - sourcesContent: Optional. An array of contents of the original source files. + * - 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(/^\)\]\}'/, '')); + } -function getStaticMethodsOnConstructorSetup(className, indent, superName) { - var string = ( indent + - 'for (var $keyName in $superName) {\n' + indent + - ' if ($superName.hasOwnProperty($keyName)) {\n' + indent + - ' $className[$keyName] = $superName[$keyName];\n' + indent + - ' }\n' + indent + - '}\n') - .replace(/\$className/g, className) - .replace(/\$keyName/g, getSuperKeyName(superName)) - .replace(/\$superName/g, superName); - return string; -} + 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 sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file'); -function getPrototypeOnConstructorSetup(className, indent, superName) { - var string = ( indent + - '$className.prototype = Object.create($protoPrototype);\n') - .replace(/\$protoPrototype/g, getProtoOfPrototypeVariableName(superName)) - .replace(/\$className/g, className); - return string; -} + if (version !== this._version) { + throw new Error('Unsupported version: ' + version); + } -function getConstructorPropertySetup(className, indent) { - var string = ( indent + - '$className.prototype.constructor = $className;\n') - .replace(/\$className/g, className); + this._names = ArraySet.fromArray(names); + this._sources = ArraySet.fromArray(sources); + this.sourceRoot = sourceRoot; + this.sourcesContent = sourcesContent; + this.file = file; - return string; -} + // `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); + } -function getSuperConstructorSetup(superClassToken, indent, superName) { - if (!superClassToken) return ''; - var string = ( '\n' + indent + - ' if ($superName && $superName.prototype) {\n' + indent + - ' $superName.apply(this, arguments);\n' + indent + - ' }\n' + indent) - .replace(/\$superName/g, superName); - return string; -} + /** + * The version of the source mapping spec that we are consuming. + */ + SourceMapConsumer.prototype._version = 3; -function getMemberFunctionCall(superVar, propertyName, superArgs) { - var string = ( - '$superPrototype.$propertyName.call($superArguments)') - .replace(/\$superPrototype/g, getProtoOfPrototypeVariableName(superVar)) - .replace(/\$propertyName/g, propertyName) - .replace(/\$superArguments/g, superArgs); - return string; -} + /** + * 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); + } + }); -function getCallParams(classElement, state) { - var params = classElement.value.params; - if (!params.length) { - return ''; - } - return state.g.source.substring( - params[0].range[0], - params[params.length - 1].range[1]); -} + /** + * 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; -function getSuperArguments(callExpression, state) { - var args = callExpression.arguments; - if (!args.length) { - return 'this'; - } - return 'this, ' + state.g.source.substring( - args[0].range[0], - args[args.length - 1].range[1]); -} + 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; -// The seed is used to generate the name for an anonymous class, -// and this seed should be unique per browser's session. -// The value of the seed looks like this: 1229588505.2969012. -var classIDSeed = Date.now() % (60 * 60 * 1000) + Math.random(); + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; -/** - * Generates a name for an anonymous class. The generated value looks like - * this: "Classkc6pcn_mniza1yvi" - * @param {String} scopeName - * @return {string} the scope name for Anonymous Class - */ -function generateAnonymousClassName(scopeName) { - classIDSeed++; - return 'Class' + - (classIDSeed).toString(36).replace('.', '_') + - (scopeName || ''); -} + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + 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'); + } -function renderMethods(traverse, object, name, path, state) { - var classElements = object.body && object.body.body || []; + // 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'); + } - move(object.body.range[0] + 1, state); - for (var i = 0; i < classElements.length; i++) { - if (classElements[i].key.name !== 'constructor') { - catchup(classElements[i].range[0], state); + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; - var memberName = classElements[i].key.name; - if (shouldMungeName(state.scopeName, memberName, state)) { - memberName = getMungedName( - state.scopeName, - memberName, - state.g.opts.minify - ); - } + 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; + } + } - var prototypeOrStatic; - if (classElements[i]['static']) { - prototypeOrStatic = ''; - } else { - prototypeOrStatic = 'prototype.'; + this._generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this._originalMappings.push(mapping); + } + } } - append(name + '.' + prototypeOrStatic + memberName + ' = ', state); - renderMethod(traverse, classElements[i], null, path, state); - append(';', state); - } - move(classElements[i].range[1], state); - } - if (classElements.length) { - append('\n', state); - } - move(object.range[1], state); -} + this._originalMappings.sort(this._compareOriginalPositions); + }; -function renderMethod(traverse, method, name, path, state) { - append(name ? 'function ' + name + '(' : 'function(', state); - append(getCallParams(method, state) + ') {', state); - move(method.value.body.range[0] + 1, state); - traverse(method.value.body, path, state); - catchup(method.value.body.range[1] - 1, state); - append('}', state); -} + /** + * 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; + } + }; -function renderSuperClass(traverse, superClass, path, state) { - append('var ' + state.superVar + ' = ', state); - move(superClass.range[0], state); - traverse(superClass, path, state); - catchup(superClass.range[1], state); - append(';\n', state); -} + /** + * 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; + }; -function renderConstructor(traverse, object, name, indent, path, state) { - var classElements = object.body && object.body.body || []; - var constructorIndex = findConstructorIndex(object); - var constructor = constructorIndex === -1 ? - null : - classElements[constructorIndex]; - if (constructor) { - move(constructorIndex === 0 ? - object.body.range[0] + 1 : - classElements[constructorIndex - 1].range[1], state); - catchup(constructor.range[0], state); - renderMethod(traverse, constructor, name, path, state); - append('\n', state); - } else { - if (object.superClass) { - append('\n' + indent, state); - } - append('function ', state); - if (object.id) { - move(object.id.range[0], state); - } - append(name, state); - if (object.id) { - move(object.id.range[1], state); - } - append('(){ ', state); - if (object.body) { - move(object.body.range[0], state); - } - append(getSuperConstructorSetup( - object.superClass, - indent, - state.superVar), state); - append('}\n', state); - } -} + /** + * 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. -var superId = 0; -function renderClassBody(traverse, object, path, state) { - var name = object.id ? object.id.name : 'constructor'; - var superClass = object.superClass; - var indent = updateIndent( - indentBefore(object.range[0], state) + ' ', - state); + 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]); + } - state = updateState( - state, - { - scopeName: object.id ? object.id.name : - generateAnonymousClassName(state.scopeName), - superVar: superClass ? '__super' + superId++ : '' - }); + return binarySearch.search(aNeedle, aMappings, aComparator); + }; - // super class - if (superClass) { - append(indent, state); - renderSuperClass(traverse, superClass, path, state); - append(getSuperProtoOfPrototypeVariable(state.superVar, indent), state); - } + /** + * 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') + }; - renderConstructor(traverse, object, name, indent, path, state); - append(getInheritanceSetup(superClass, name, indent, state.superVar), state); - renderMethods(traverse, object, name, path, state); -} + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + this._compareGeneratedPositions); + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } -/** - * @public - */ -function visitClassExpression(traverse, object, path, state) { - var indent = updateIndent( - indentBefore(object.range[0], state) + ' ', - state); - var name = object.id ? object.id.name : 'constructor'; + return { + source: null, + line: null, + column: null, + name: null + }; + }; - append('(function() {\n', state); - renderClassBody(traverse, object, path, state); - append(indent + 'return ' + name + ';\n', state); - append(indent.substring(0, indent.length - 2) + '})()', state); - return false -} + /** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } -visitClassExpression.test = function(object, path, state) { - return object.type === Syntax.ClassExpression; -}; + if (this.sourceRoot) { + aSource = util.relative(this.sourceRoot, aSource); + } -/** - * @public - */ -function visitClassDeclaration(traverse, object, path, state) { - state.g.indentBy--; - renderClassBody(traverse, object, path, state); - state.g.indentBy++; - return false; -} + if (this._sources.has(aSource)) { + return this.sourcesContent[this._sources.indexOf(aSource)]; + } -visitClassDeclaration.test = function(object, path, state) { - return object.type === Syntax.ClassDeclaration; -}; + var url; + if (this.sourceRoot + && (url = util.urlParse(this.sourceRoot))) { + // XXX: file:// URIs and absolute paths lead to unexpected behavior for + // many users. We can help them out when they expect file:// URIs to + // behave like it would if they were running a local HTTP server. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. + var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); + if (url.scheme == "file" + && this._sources.has(fileUriAbsPath)) { + return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + } + if ((!url.path || url.path == "/") + && this._sources.has("/" + aSource)) { + return this.sourcesContent[this._sources.indexOf("/" + aSource)]; + } + } -/** - * @public - */ -function visitSuperCall(traverse, object, path, state) { - if (path[0].type === Syntax.CallExpression) { - append(state.superVar + - '.call(' + getSuperArguments(path[0], state) + ')', state); - move(path[0].range[1], state); - } else if (path[0].type === Syntax.MemberExpression) { - append(getMemberFunctionCall( - state.superVar, - path[0].property.name, - getSuperArguments(path[1], state)), state); - move(path[1].range[1], state); - } - return false; -} + throw new Error('"' + aSource + '" is not in the SourceMap.'); + }; -visitSuperCall.test = function(object, path, state) { - return state.superVar && object.type === Syntax.Identifier && - object.name === 'super'; -}; + /** + * 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') + }; -/** - * @public - */ -function visitPrivateProperty(traverse, object, path, state) { - var type = path[0] ? path[0].type : null; - if (type !== Syntax.Property) { - if (type === Syntax.MemberExpression) { - type = path[0].object ? path[0].object.type : null; - if (type === Syntax.Identifier && - path[0].object.range[0] === object.range[0]) { - // Identifier is a variable that appears "private". - return; + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); } - } else { - // Other syntax that are neither Property nor MemberExpression. - return; - } - } - var oldName = object.name; - var newName = getMungedName( - state.scopeName, - oldName, - state.g.opts.minify - ); - append(newName, state); - move(object.range[1], state); -} + 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) + }; + } -visitPrivateProperty.test = function(object, path, state) { - return object.type === Syntax.Identifier && - shouldMungeName(state.scopeName, object.name, state); -}; + return { + line: null, + column: null + }; + }; + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; -exports.visitClassDeclaration = visitClassDeclaration; -exports.visitClassExpression = visitClassExpression; -exports.visitSuperCall = visitSuperCall; -exports.visitPrivateProperty = visitPrivateProperty; + /** + * 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. + * @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; -})() -},{"../lib/utils":8,"../lib/docblock":4,"esprima":9,"base62":15}],6:[function(require,module,exports){ -(function(){/** - * 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 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."); + } -var Syntax = require('esprima').Syntax; + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; -var catchup = require('../lib/utils').catchup; -var append = require('../lib/utils').append; -var move = require('../lib/utils').move; -var getDocblock = require('../lib/utils').getDocblock; + exports.SourceMapConsumer = SourceMapConsumer; -var FALLBACK_TAGS = require('./xjs').knownTags; -var renderXJSExpression = require('./xjs').renderXJSExpression; -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. +},{"./array-set":6,"./base64-vlq":7,"./binary-search":9,"./util":13,"amdefine":14}],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, require); +} +define(function (require, exports, module) { -var JSX_ATTRIBUTE_RENAMES = { - 'class': 'className', - cxName: 'className' -}; + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; -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(',') + ')'; - } + /** + * 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 = []; + this._sourcesContents = null; } -}; -function visitReactTag(traverse, object, path, state) { - var jsxObjIdent = getDocblock(state).jsx; + SourceMapGenerator.prototype._version = 3; - catchup(object.openingElement.range[0], state); + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; - if (object.name.namespace) { - throw new Error( - 'Namespace tags are not supported. ReactJSX is not XML.'); - } + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } - var isFallbackTag = FALLBACK_TAGS[object.name.name]; - append( - (isFallbackTag ? jsxObjIdent + '.' : '') + (object.name.name) + '(', - state - ); + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; - move(object.name.range[1], state); + if (mapping.name) { + newMapping.name = mapping.name; + } + } - var childrenToRender = object.children.filter(function(child) { - return !(child.type === Syntax.Literal && !child.value.match(/\S/)); - }); + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; - // if we don't have any attributes, pass in null - if (object.attributes.length === 0) { - append('null', state); - } + /** + * 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); - // write attributes - object.attributes.forEach(function(attr, index) { - catchup(attr.range[0], state); - if (attr.name.namespace) { - throw new Error( - 'Namespace attributes are not supported. ReactJSX is not XML.'); - } - var name = JSX_ATTRIBUTE_RENAMES[attr.name.name] || attr.name.name; - var isFirst = index === 0; - var isLast = index === object.attributes.length - 1; + this._validateMapping(generated, original, source, name); - if (isFirst) { - append('{', state); - } + 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 + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } - append(quoteAttrName(name), state); - append(':', state); + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; - if (!attr.value) { - state.g.buffer += 'true'; - state.g.position = attr.name.range[1]; - if (!isLast) { - append(',', state); + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; } - } else if (JSX_ATTRIBUTE_TRANSFORMS[attr.name.name]) { - move(attr.value.range[0], state); - append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state); - move(attr.value.range[1], state); - if (!isLast) { - append(',', state); + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); } - } else if (attr.value.type === Syntax.Literal) { - move(attr.value.range[0], state); - renderXJSLiteral(attr.value, isLast, state); - } else { - move(attr.value.range[0], state); - renderXJSExpression(traverse, attr.value, isLast, path, state); - } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); - if (isLast) { - append('}', state); - } + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.original) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.original.line, + column: mapping.original.column + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + mapping.original.line = original.line; + mapping.original.column = original.column; + if (original.name !== null && mapping.name !== null) { + // Only use the identifier name if it's an identifier + // in both SourceMaps + mapping.name = original.name; + } + } + } - catchup(attr.range[1], state); - }); + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } - if (!object.selfClosing) { - catchup(object.openingElement.range[1] - 1, state); - move(object.openingElement.range[1], state); - } + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } - // separate props and children arguments - append(', ', state); + }, this); + this._sources = newSources; + this._names = newNames; - // filter out whitespace - if (childrenToRender.length > 0) { - if (childrenToRender.length > 1) { - append('[', state); - } - object.children.forEach(function(child) { - if (child.type === Syntax.Literal && !child.value.match(/\S/)) { + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * 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; } - 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.XJSExpression) { - renderXJSExpression(traverse, child, isLast, path, state); - } else { - traverse(child, path, state); - if (!isLast) { - append(',', state); - state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1'); - } + 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.'); } + }; - catchup(child.range[1], state); - }); - } else { - append('null', state); + function cmpLocation(loc1, loc2) { + var cmp = (loc1 && loc1.line) - (loc2 && loc2.line); + return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column); } - if (object.selfClosing) { - // everything up to /> - catchup(object.openingElement.range[1] - 2, state); - move(object.openingElement.range[1], state); - } else { - // everything up to - catchup(object.closingElement.range[0], state); - move(object.closingElement.range[1], state); + function strcmp(str1, str2) { + str1 = str1 || ''; + str2 = str2 || ''; + return (str1 > str2) - (str1 < str2); } - if (childrenToRender.length > 0) { - if (childrenToRender.length > 1) { - append(']', state); - } + function cmpMapping(mappingA, mappingB) { + return cmpLocation(mappingA.generated, mappingB.generated) || + cmpLocation(mappingA.original, mappingB.original) || + strcmp(mappingA.source, mappingB.source) || + strcmp(mappingA.name, mappingB.name); } - append(')', state); - return false; -} -visitReactTag.test = function(object, path, state) { - // only run react when react @jsx namespace is specified in docblock - var jsx = getDocblock(state).jsx; - return object.type === Syntax.XJSElement && jsx && jsx.length; -}; + /** + * 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; -exports.visitReactTag = visitReactTag; + // The mappings must be guaranteed 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(cmpMapping); -})() -},{"../lib/utils":8,"./xjs":11,"esprima":9}],7:[function(require,module,exports){ -(function(){/** - * 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"; + 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) { + if (!cmpMapping(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } -var Syntax = require('esprima').Syntax; -var catchup = require('../lib/utils').catchup; -var append = require('../lib/utils').append; -var getDocblock = require('../lib/utils').getDocblock; + result += base64VLQ.encode(mapping.generated.column + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generated.column; -/** - * 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) { + if (mapping.source && mapping.original) { + result += base64VLQ.encode(this._sources.indexOf(mapping.source) + - previousSource); + previousSource = this._sources.indexOf(mapping.source); - var displayName = object.id.name; - catchup(object.init['arguments'][0].range[0] + 1, state); - append("displayName: '" + displayName + "',", state); - } -} + // lines are stored 0-based in SourceMap spec version 3 + result += base64VLQ.encode(mapping.original.line - 1 + - previousOriginalLine); + previousOriginalLine = mapping.original.line - 1; -/** - * Will only run on @jsx files for now. - */ -visitReactDisplayName.test = function(object, path, state) { - return object.type === Syntax.VariableDeclarator && !!getDocblock(state).jsx; -}; + result += base64VLQ.encode(mapping.original.column + - previousOriginalColumn); + previousOriginalColumn = mapping.original.column; -exports.visitReactDisplayName = visitReactDisplayName; + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } -})() -},{"../lib/utils":8,"esprima":9}],15:[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"] + return result; + }; - 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 - }; + /** + * 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; + } + if (this._sourcesContents) { + map.sourcesContent = map.sources.map(function (source) { + if (map.sourceRoot) { + source = util.relative(map.sourceRoot, source); + } + return Object.prototype.hasOwnProperty.call( + this._sourcesContents, util.toSetString(source)) + ? this._sourcesContents[util.toSetString(source)] + : null; + }, this); + } + return map; + }; - return my; -}({})); + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; -module.exports = Base62 -},{}],12:[function(require,module,exports){ + exports.SourceMapGenerator = SourceMapGenerator; + +}); + +},{"./array-set":6,"./base64-vlq":7,"./util":13,"amdefine":14}],12:[function(require,module,exports){ /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors @@ -7974,2162 +7661,2536 @@ module.exports = Base62 * http://opensource.org/licenses/BSD-3-Clause */ if (typeof define !== 'function') { - var define = require('amdefine')(module); + var define = require('amdefine')(module, require); } define(function (require, exports, module) { - var base64VLQ = require('./base64-vlq'); + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; 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: + * 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. * - * - file: The filename of the generated source. - * - sourceRoot: An optional root for all URLs in this source map. + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. */ - function 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 = []; - this._sourcesContents = null; + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); } - SourceMapGenerator.prototype._version = 3; - /** - * Creates a new SourceMapGenerator based on a SourceMapConsumer + * Creates a SourceNode from generated code and a SourceMapConsumer. * - * @param aSourceMapConsumer The SourceMap. + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code */ - SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); - if (mapping.source) { - newMapping.source = mapping.source; - if (sourceRoot) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; - if (mapping.name) { - newMapping.name = mapping.name; + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); } } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); - generator.addMapping(newMapping); - }); + // Copy sourcesContent into SourceNode aSourceMapConsumer.sources.forEach(function (sourceFile) { var content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content) { - generator.setSourceContent(sourceFile, content); + node.setSourceContent(sourceFile, content); } }); - return generator; + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } }; /** - * 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: + * Add a chunk of generated JS to this source node. * - * - 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. + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. */ - 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); + 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; + }; - if (name && !this._names.has(name)) { - this._names.add(name); + /** + * 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]); } - - this._mappings.push({ - generated: generated, - original: original, - source: source, - name: name - }); - }; + } + 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; + }; /** - * Set the source content for a source file. + * 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. */ - SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot) { - source = util.relative(this._sourceRoot, source); + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + this.children.forEach(function (chunk) { + if (chunk instanceof SourceNode) { + chunk.walk(aFn); } - - if (aSourceContent !== null) { - // Add the source content to the _sourcesContents map. - // Create a new _sourcesContents map if the property is null. - if (!this._sourcesContents) { - this._sourcesContents = {}; - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else { - // Remove the source file from the _sourcesContents map. - // If the _sourcesContents map is empty, set the property to null. - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); } } - }; + }, this); + }; /** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. + * @param aSep The separator. */ - SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { - // If aSourceFile is omitted, we will use the file property of the SourceMap - if (!aSourceFile) { - aSourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - // Make "aSourceFile" relative if an absolute Url is passed. - if (sourceRoot) { - aSourceFile = util.relative(sourceRoot, aSourceFile); + 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); } - // Applying the SourceMap can add and remove items from the sources and - // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); - - // Find mappings for the "aSourceFile" - this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.original) { - // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.original.line, - column: mapping.original.column - }); - if (original.source !== null) { - // Copy mapping - if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; - } - mapping.original.line = original.line; - mapping.original.column = original.column; - if (original.name !== null && mapping.name !== null) { - // Only use the identifier name if it's an identifier - // in both SourceMaps - mapping.name = original.name; - } - } - } - - var source = mapping.source; - if (source && !newSources.has(source)) { - newSources.add(source); - } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; - var name = mapping.name; - if (name && !newNames.has(name)) { - newNames.add(name); - } + /** + * 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; + }; - }, this); - this._sources = newSources; - this._names = newNames; + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; - // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - if (sourceRoot) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + this.children.forEach(function (chunk) { + if (chunk instanceof SourceNode) { + chunk.walkSourceContents(aFn); } }, this); + Object.keys(this.sourceContents).forEach(function (sourceFileKey) { + aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); + }, this); }; /** - * 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. + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. */ - 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.'); - } + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + 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 + }, + name: original.name + }); + sourceMappingActive = true; + } else if (sourceMappingActive) { + map.addMapping({ + generated: { + line: generated.line, + column: generated.column + } + }); + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); - function cmpLocation(loc1, loc2) { - var cmp = (loc1 && loc1.line) - (loc2 && loc2.line); - return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column); - } + return { code: generated.code, map: map }; + }; - function strcmp(str1, str2) { - str1 = str1 || ''; - str2 = str2 || ''; - return (str1 > str2) - (str1 < str2); - } + exports.SourceNode = SourceNode; - function cmpMapping(mappingA, mappingB) { - return cmpLocation(mappingA.generated, mappingB.generated) || - cmpLocation(mappingA.original, mappingB.original) || - strcmp(mappingA.source, mappingB.source) || - strcmp(mappingA.name, mappingB.name); - } +}); + +},{"./source-map-generator":11,"./util":13,"amdefine":14}],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, require); +} +define(function (require, exports, module) { /** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. + * 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. */ - 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(cmpMapping); - - 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) { - if (!cmpMapping(mapping, this._mappings[i - 1])) { - continue; - } - result += ','; - } - } + 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; - result += base64VLQ.encode(mapping.generated.column - - previousGeneratedColumn); - previousGeneratedColumn = mapping.generated.column; + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - if (mapping.source && mapping.original) { - result += base64VLQ.encode(this._sources.indexOf(mapping.source) - - previousSource); - previousSource = this._sources.indexOf(mapping.source); + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; - // lines are stored 0-based in SourceMap spec version 3 - result += base64VLQ.encode(mapping.original.line - 1 - - previousOriginalLine); - previousOriginalLine = mapping.original.line - 1; + function urlGenerate(aParsedUrl) { + var url = aParsedUrl.scheme + "://"; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + "@" + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; + } + exports.urlGenerate = urlGenerate; - result += base64VLQ.encode(mapping.original.column - - previousOriginalColumn); - previousOriginalColumn = mapping.original.column; + function join(aRoot, aPath) { + var url; - if (mapping.name) { - result += base64VLQ.encode(this._names.indexOf(mapping.name) - - previousName); - previousName = this._names.indexOf(mapping.name); - } - } - } + if (aPath.match(urlRegexp)) { + return aPath; + } - return result; - }; + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } - /** - * 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; - } - if (this._sourcesContents) { - map.sourcesContent = map.sources.map(function (source) { - if (map.sourceRoot) { - source = util.relative(map.sourceRoot, source); - } - return Object.prototype.hasOwnProperty.call( - this._sourcesContents, util.toSetString(source)) - ? this._sourcesContents[util.toSetString(source)] - : null; - }, this); - } - return map; - }; + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; /** - * Render the source map being generated to a string. + * Because behavior goes wacky when you set `__proto__` on objects, 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 */ - SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { - return JSON.stringify(this); - }; + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; - exports.SourceMapGenerator = SourceMapGenerator; + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; }); -},{"./base64-vlq":16,"./util":17,"./array-set":18,"amdefine":19}],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 +},{"amdefine":14}],14:[function(require,module,exports){ +(function(process,__filename){/** vim: et:ts=4:sw=4:sts=4 + * @license amdefine 0.0.5 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 */ -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'); +/*jslint node: true */ +/*global module, process */ +'use strict'; - /** - * 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. - * - sourcesContent: Optional. An array of contents of the original source files. - * - 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 path = require('path'); + +/** + * Creates a define for node. + * @param {Object} module the "module" object that is defined by Node for the + * current module. + * @param {Function} [require]. 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, require) { + var defineCache = {}, + loaderCache = {}, + alreadyCalled = false, + 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; + } + } + } } - 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 sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file'); + function normalize(name, baseName) { + var baseParts; - if (version !== this._version) { - throw new Error('Unsupported version: ' + version); + //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; } - this._names = ArraySet.fromArray(names); - this._sources = ArraySet.fromArray(sources); - this.sourceRoot = sourceRoot; - this.sourcesContent = sourcesContent; - this.file = file; + /** + * Create the normalize() function passed to a loader plugin's + * normalize method. + */ + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } - // `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); - } + function makeLoad(id) { + function load(value) { + loaderCache[id] = value; + } - /** - * The version of the source mapping spec that we are consuming. - */ - SourceMapConsumer.prototype._version = 3; + 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. + require = require || function req() { + return module.require.apply(module, arguments); + }; - /** - * 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); - } - }); + function runFactory(id, deps, factory) { + var r, e, m, result; - /** - * 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; + if (id) { + e = loaderCache[id] = {}; + m = { + id: id, + uri: __filename, + exports: e + }; + r = makeRequire(require, 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; - while (str.length > 0) { - if (str.charAt(0) === ';') { - generatedLine++; - str = str.slice(1); - previousGeneratedColumn = 0; + //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(require, e, m, module.id); } - else if (str.charAt(0) === ',') { - str = str.slice(1); + + //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); + }); } - else { - mapping = {}; - mapping.generatedLine = generatedLine; - // Generated column. - temp = base64VLQ.decode(str); - mapping.generatedColumn = previousGeneratedColumn + temp.value; - previousGeneratedColumn = mapping.generatedColumn; - str = temp.rest; + //Call the factory with the right dependencies. + if (typeof factory === 'function') { + result = factory.apply(module.exports, deps); + } else { + result = factory; + } - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - // Original source. - temp = base64VLQ.decode(str); - 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'); + if (result !== undefined) { + m.exports = result; + if (id) { + loaderCache[id] = m.exports; } + } + } - // 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'); - } + stringRequire = function (systemRequire, exports, module, id, relId) { + //Split the ID by a ! so that + var index = id.indexOf('!'), + originalId = id, + prefix, plugin; - // Original column. - temp = base64VLQ.decode(str); - mapping.originalColumn = previousOriginalColumn + temp.value; - previousOriginalColumn = mapping.originalColumn; - str = temp.rest; + if (index === -1) { + id = normalize(id, relId); - 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; + //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); - this._generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - this._originalMappings.push(mapping); - } - } - } + plugin = stringRequire(systemRequire, exports, module, prefix, relId); - this._originalMappings.sort(this._compareOriginalPositions); - }; + if (plugin.normalize) { + id = plugin.normalize(id, makeNormalize(relId)); + } else { + //Normalize the ID normally. + id = normalize(id, relId); + } - /** - * 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; - } - }; + if (loaderCache[id]) { + return loaderCache[id]; + } else { + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); - /** - * 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; + return loaderCache[id]; + } + } }; - /** - * 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]); - } + //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; + } - return binarySearch.search(aNeedle, aMappings, aComparator); - }; + if (deps && !Array.isArray(deps)) { + factory = deps; + deps = undefined; + } - /** - * 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') - }; + if (!deps) { + deps = ['require', 'exports', 'module']; + } - var mapping = this._findMapping(needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - this._compareGeneratedPositions); + //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); + } + } - if (mapping) { - var source = util.getArg(mapping, 'source', null); - if (source && this.sourceRoot) { - source = util.join(this.sourceRoot, source); + //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]; } - return { - source: source, - 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 - }; + if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } }; - /** - * Returns the original source content. The only argument is - * the url of the original source file. Returns null if no - * original source content is availible. - */ - SourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource) { - if (!this.sourcesContent) { - return null; - } + define.amd = {}; - if (this.sourceRoot) { - // Try to remove the sourceRoot - var relativeUrl = util.relative(this.sourceRoot, aSource); - if (this._sources.has(relativeUrl)) { - return this.sourcesContent[this._sources.indexOf(relativeUrl)]; - } - } + return define; +} - if (this._sources.has(aSource)) { - return this.sourcesContent[this._sources.indexOf(aSource)]; - } +module.exports = amdefine; - throw new Error('"' + aSource + '" is not in the SourceMap.'); - }; +})(require("__browserify_process"),"/../node_modules/source-map/node_modules/amdefine/amdefine.js") +},{"__browserify_process":3,"path":2}],15:[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 */ - /** - * 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') - }; +'use strict'; +var runScripts; - if (this.sourceRoot) { - needle.source = util.relative(this.sourceRoot, needle.source); - } +var transform = require('./fbtransform/lib/transform').transform; +var visitors = require('./fbtransform/visitors').transformVisitors; +var transform = transform.bind(null, visitors.react); +var docblock = require('./fbtransform/lib/docblock'); - var mapping = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - this._compareOriginalPositions); +var headEl = document.getElementsByTagName('head')[0]; - if (mapping) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null) - }; - } +exports.transform = transform; - return { - line: null, - column: null - }; - }; +exports.exec = function(code) { + return eval(transform(code)); +}; - SourceMapConsumer.GENERATED_ORDER = 1; - SourceMapConsumer.ORIGINAL_ORDER = 2; +var run = exports.run = function(code) { + var jsx = docblock.parseAsObject(docblock.extract(code)).jsx; - /** - * 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. - * @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 functionBody = jsx ? transform(code).code : code; + var scriptEl = document.createElement('script'); - 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."); + scriptEl.innerHTML = functionBody; + headEl.appendChild(scriptEl); +}; + +if (typeof window === "undefined" || window === null) { + return; +} + +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); +}; - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source; - if (source && sourceRoot) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name - }; - }).forEach(aCallback, context); - }; +runScripts = function() { + var scripts = document.getElementsByTagName('script'); + scripts = Array.prototype.slice.call(scripts); + var jsxScripts = scripts.filter(function(script) { + return script.type === 'text/jsx'; + }); - exports.SourceMapConsumer = SourceMapConsumer; + 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); +} -},{"./util":17,"./binary-search":20,"./array-set":18,"./base64-vlq":16,"amdefine":19}],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 +},{"./fbtransform/lib/docblock":16,"./fbtransform/lib/transform":17,"./fbtransform/visitors":23}],16:[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. */ -if (typeof define !== 'function') { - var define = require('amdefine')(module); + +var docblockRe = /^\s*(\/\*\*(.|\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 ''; } -define(function (require, exports, module) { - var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; - var util = require('./util'); - /** - * SourceNodes provide a way to abstract over interpolating/concatenating - * snippets of generated JavaScript source code while maintaining the line and - * column information associated with the original source code. - * - * @param aLine The original line number. - * @param aColumn The original column number. - * @param aSource The original source's filename. - * @param aChunks Optional. An array of strings which are snippets of - * generated JS, or other SourceNodes. - * @param aName The original identifier. - */ - function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine === undefined ? null : aLine; - this.column = aColumn === undefined ? null : aColumn; - this.source = aSource === undefined ? null : aSource; - this.name = aName === undefined ? null : aName; - if (aChunks != null) this.add(aChunks); +var commentStartRe = /^\/\*\*?/; +var commentEndRe = /\*\/$/; +var wsRe = /[\t ]+/g; +var stringStartRe = /(\n|^) *\*/g; +var multilineRe = /(?:^|\n) *(@[^\n]*?) *\n *([^@\n\s][^@\n]+?) *\n/g; +var propertyRe = /(?:^|\n) *@(\S+) *([^\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(); - /** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - */ - SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { - // The SourceNode we want to fill with the generated code - // and the SourceMap - var node = new SourceNode(); + var result = []; + var match; + while (match = propertyRe.exec(docblock)) { + result.push([match[1], match[2]]); + } - // The generated code - // Processed fragments are removed from this array. - var remainingLines = aGeneratedCode.split('\n'); + return result; +} - // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; +/** + * 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; +} - // The generate SourceNodes we need a code range. - // To extract it current and last mapping is used. - // Here we store the last mapping. - var lastMapping = null; - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping === null) { - // We add the generated code until the first mapping - // to the SourceNode without any mapping. - // Each line is added as separate string. - while (lastGeneratedLine < mapping.generatedLine) { - node.add(remainingLines.shift() + "\n"); - lastGeneratedLine++; - } - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - node.add(nextLine.substr(0, mapping.generatedColumn)); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - } else { - // We add the code from "lastMapping" to "mapping": - // First check if there is a new line in between. - if (lastGeneratedLine < mapping.generatedLine) { - var code = ""; - // Associate full lines with "lastMapping" - do { - code += remainingLines.shift() + "\n"; - lastGeneratedLine++; - lastGeneratedColumn = 0; - } while (lastGeneratedLine < mapping.generatedLine); - // When we reached the correct line, we add code until we - // reach the correct column too. - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - code += nextLine.substr(0, mapping.generatedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - // Create the SourceNode. - addMappingWithCode(lastMapping, code); - } else { - // There is no new line in between. - // Associate the code between "lastGeneratedColumn" and - // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[0]; - var code = nextLine.substr(0, mapping.generatedColumn - - lastGeneratedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn - - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - } - } - lastMapping = mapping; - }, this); - // We have processed all mappings. - // Associate the remaining code in the current line with "lastMapping" - // and add the remaining lines without any mapping - addMappingWithCode(lastMapping, remainingLines.join("\n")); +exports.extract = extract; +exports.parse = parse; +exports.parseAsObject = parseAsObject; - // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - node.setSourceContent(sourceFile, content); - } - }); +},{}],17:[function(require,module,exports){ +(function(){/** + * 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*/ +/*jslint node: true*/ +"use strict"; - return node; +/** + * Syntax transfomer for javascript. Takes the source in, spits the source + * out. Tries to maintain readability and preserve whitespace and line numbers + * where posssible. + * + * Support + * - ES6 class transformation + private property munging, see ./classes.js + * - React XHP style syntax transformations, see ./react.js + * - Bolt XHP style syntax transformations, see ./bolt.js + * + * The general flow is the following: + * - Parse the source with our customized esprima-parser + * https://github.com/voloko/esprima. We have to customize the parser to + * support non-standard XHP-style syntax. We parse the source range: true + * option that forces esprima to return positions in the source within + * resulting parse tree. + * + * - Traverse resulting syntax tree, trying to apply a set of visitors to each + * node. Each visitor should provide a .test() function that tests if the + * visitor can process a given node. + * + * - Visitor is responsible for code generation for a given syntax node. + * Generated code is stored in state.g.buffer that is passed to every + * visitor. It's up to the visitor to process the code the way it sees fit. + * All of the current visitors however use both the node and the original + * source to generate transformed code. They use nodes to generate new + * code and they copy the original source, preserving whitespace and comments, + * for the parts they don't care about. + */ +var esprima = require('esprima'); - function addMappingWithCode(mapping, code) { - if (mapping.source === undefined) { - node.add(code); - } else { - node.add(new SourceNode(mapping.originalLine, - mapping.originalColumn, - mapping.source, - code, - mapping.name)); - } - } - }; +var createState = require('./utils').createState; +var catchup = require('./utils').catchup; - /** - * 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; - }; +/** + * @param {object} object + * @param {function} visitor + * @param {array} path + * @param {object} state + */ +function traverse(object, path, state) { + var key, child; - /** - * 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]); - } + if (walker(traverse, object, path, state) === false) { + return; + } + path.unshift(object); + for (key in object) { + // skip obviously wrong attributes + if (key === 'range' || key === 'loc') { + continue; } - else if (aChunk instanceof SourceNode || typeof aChunk === "string") { - this.children.unshift(aChunk); + if (object.hasOwnProperty(key)) { + child = object[key]; + if (typeof child === 'object' && child !== null) { + child.range && catchup(child.range[0], state); + traverse(child, path, state); + child.range && catchup(child.range[1], state); + } } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); + } + path.shift(); +} + +function walker(traverse, object, path, state) { + var visitors = state.g.visitors; + for (var i = 0; i < visitors.length; i++) { + if (visitors[i].test(object, path, state)) { + return visitors[i](traverse, object, path, state); } - 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, - name: this.name }); - } - } - }, this); - }; +function runPass(source, visitors, 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, options); + state.g.originalProgramAST = ast; + state.g.visitors = visitors; - /** - * 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; - }; + if (options.sourceMap) { + var SourceMapGenerator = require('source-map').SourceMapGenerator; + state.g.sourceMap = new SourceMapGenerator({ file: 'transformed.js' }); + } + traverse(ast, [], state); + catchup(source.length, state); + return state; +} - /** - * 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; - }; +/** + * 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 || {}; - /** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file - */ - SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; + var state = runPass(source, visitors, options); + var sourceMap = state.g.sourceMap; - /** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. - */ - SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - this.children.forEach(function (chunk) { - if (chunk instanceof SourceNode) { - chunk.walkSourceContents(aFn); - } - }, this); - Object.keys(this.sourceContents).forEach(function (sourceFileKey) { - aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); - }, this); + if (sourceMap) { + return { + sourceMap: sourceMap, + sourceMapFilename: options.filename || 'source.js', + code: state.g.buffer + }; + } else { + return { + code: state.g.buffer }; + } +} - /** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. - */ - SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; - }; - /** - * Returns the string representation of this source node along with a source - * map. - */ - SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - 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 - }, - name: original.name - }); - sourceMappingActive = true; - } else if (sourceMappingActive) { - map.addMapping({ - generated: { - line: generated.line, - column: generated.column - } - }); - sourceMappingActive = false; - } - chunk.split('').forEach(function (ch) { - if (ch === '\n') { - generated.line++; - generated.column = 0; - } else { - generated.column++; - } - }); - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); +exports.transform = transform; + +})() +},{"./utils":18,"esprima":4,"source-map":5}],18:[function(require,module,exports){ +(function(){/** + * 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*/ + +/** + * State represents the given parser state. It has a 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, transformOptions) { + return { + /** + * Name of the super class variable + * @type {String} + */ + superVar: '', + /** + * Name of the enclosing class scope + * @type {String} + */ + scopeName: '', + /** + * 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, - return { code: generated.code, map: map }; - }; + /** + * Cached parsed docblock (see getDocblock) + * @type {object} + */ + docblock: null, - exports.SourceNode = SourceNode; + /** + * Whether the thing was used + * @type {Boolean} + */ + tagNamespaceUsed: false, -}); + /** + * If using bolt xjs transformation + * @type {Boolean} + */ + isBolt: undefined, -},{"./source-map-generator":12,"./util":17,"amdefine":19}],21:[function(require,module,exports){ -// shim for using process in browser + /** + * Whether to record source map (expensive) or not + * @type {SourceMapGenerator|null} + */ + sourceMap: null, -var process = module.exports = {}; + /** + * Filename of the file being processed. Will be returned as a source + * attribute in the source map + */ + sourceMapFilename: 'source.js', -process.nextTick = (function () { - var canSetImmediate = typeof window !== 'undefined' - && window.setImmediate; - var canPost = typeof window !== 'undefined' - && window.postMessage && window.addEventListener - ; + /** + * Only when source map is used: last line in the source for which + * source map was generated + * @type {Number} + */ + sourceLine: 1, - if (canSetImmediate) { - return function (f) { return window.setImmediate(f) }; - } + /** + * Only when source map is used: last line in the buffer for which + * source map was generated + * @type {Number} + */ + bufferLine: 1, - 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); + /** + * The top-level Program AST for the original file. + */ + originalProgramAST: null, - return function nextTick(fn) { - queue.push(fn); - window.postMessage('process-tick', '*'); - }; + sourceColumn: 0, + bufferColumn: 0 } - - 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'); -}; - -},{}],19:[function(require,module,exports){ -(function(process,__filename){/** vim: et:ts=4:sw=4:sts=4 - * @license amdefine 0.0.5 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 +/** + * Updates a copy of a given state with "update" and returns an updated state. + * + * @param {Object} state + * @param {Object} update + * @return {Object} */ - -/*jslint node: true */ -/*global module, process */ -'use strict'; - -var path = require('path'); +function updateState(state, update) { + return { + g: state.g, + superVar: update.superVar || state.superVar, + scopeName: update.scopeName || state.scopeName + }; +} /** - * Creates a define for node. - * @param {Object} module the "module" object that is defined by Node for the - * current module. - * @param {Function} [require]. 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. + * 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 amdefine(module, require) { - var defineCache = {}, - loaderCache = {}, - alreadyCalled = false, - 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('/'); - } - } +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 + }); - return name; + // 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++; } - - /** - * Create the normalize() function passed to a loader plugin's - * normalize method. - */ - function makeNormalize(relName) { - return function (name) { - return normalize(name, relName); - }; + // 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; +} - function makeLoad(id) { - function load(value) { - loaderCache[id] = value; - } +/** + * Applies `catchup` but passing in a function that removes any non-whitespace + * characters. + */ +var re = /(\S)/g; +function stripNonWhite(value) { + return value.replace(re, function() { + return ''; + }); +} +/** + * Catches up as `catchup` but turns each non-white character into a space. + */ +function catchupWhiteSpace(end, state) { + catchup(end, state, stripNonWhite); +} - 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'); - }; +/** + * 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; + } - return load; + 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; +} - 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. +/** + * Appends a string of text to the buffer + * @param {String} string + * @param {Object} state + */ +function append(string, state) { + if (state.g.sourceMap && string) { + 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 = string.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 += string; +} - //Convert the dependencies to modules. - deps = deps.map(function (depName) { - return stringRequire(systemRequire, exports, module, depName, relId); - }); +/** + * 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; +} - //Wait for next tick to call back the require call. - process.nextTick(function () { - callback.apply(null, deps); - }); - } - } +/** + * 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; - amdRequire.toUrl = function (filePath) { - if (filePath.indexOf('.') === 0) { - return normalize(filePath, path.dirname(module.filename)); - } else { - return filePath; - } - }; + 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); +} - return amdRequire; - }; +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; +} - //Favor explicit value, passed in if the module wants to support Node 0.4. - require = require || function req() { - return module.require.apply(module, arguments); - }; +exports.catchup = catchup; +exports.catchupWhiteSpace = catchupWhiteSpace; +exports.append = append; +exports.move = move; +exports.updateIndent = updateIndent; +exports.indentBefore = indentBefore; +exports.updateState = updateState; +exports.createState = createState; +exports.getDocblock = getDocblock; - function runFactory(id, deps, factory) { - var r, e, m, result; +})() +},{"./docblock":16}],19:[function(require,module,exports){ +(function(){/** + * 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"; - if (id) { - e = loaderCache[id] = {}; - m = { - id: id, - uri: __filename, - exports: e - }; - r = makeRequire(require, 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; +/** + * Desugarizer for ES6 minimal class proposal. See + * http://wiki.ecmascript.org/doku.php?id=harmony:proposals + * + * Does not require any runtime. Preserves whitespace and comments. + * Supports a class declaration with methods, super calls and inheritance. + * Currently does not support for getters and setters, since there's a very + * low probability we're going to use them anytime soon. + * + * Additional features: + * - Any member with private name (the name with prefix _, such _name) inside + * the class's scope will be munged. This would will to eliminate the case + * of sub-class accidentally overriding the super-class's provate properties + * also discouage people from accessing private members that they should not + * access. However, quoted property names don't get munged. + * + * class SkinnedMesh extends require('THREE').Mesh { + * + * update(camera) { + * camera.code = 'iphone' + * super.update(camera); + * } + * + * / + * * @constructor + * / + * constructor(geometry, materials) { + * super(geometry, materials); + * + * super.update(1); + * + * this.identityMatrix = new THREE.Matrix4(); + * this.bones = []; + * this.boneMatrices = []; + * this._name = 'foo'; + * } + * + * / + * * some other code + * / + * readMore() { + * + * } + * + * _doSomething() { + * + * } + * } + * + * should be converted to + * + * var SkinnedMesh = (function() { + * var __super = require('parent').Mesh; + * + * / + * * @constructor + * / + * function SkinnedMesh(geometry, materials) { + * __super.call(this, geometry, materials); + * + * __super.prototype.update.call(this, 1); + * + * this.identityMatrix = new THREE.Matrix4(); + * this.bones = []; + * this.boneMatrices = []; + * this.$SkinnedMesh_name = 'foo'; + * } + * SkinnedMesh.prototype = Object.create(__super.prototype); + * SkinnedMesh.prototype.constructor = SkinnedMesh; + * + * / + * * @param camera + * / + * SkinnedMesh.prototype.update = function(camera) { + * camera.code = 'iphone' + * __super.prototype.update.call(this, camera); + * }; + * + * SkinnedMesh.prototype.readMore = function() { + * + * }; + * + * SkinnedMesh.prototype.$SkinnedMesh_doSomething = function() { + * + * }; + * + * return SkinnedMesh; + * })(); + * + */ +var Syntax = require('esprima').Syntax; +var base62 = require('base62'); - //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(require, e, m, module.id); - } +var catchup = require('../lib/utils').catchup; +var append = require('../lib/utils').append; +var move = require('../lib/utils').move; +var indentBefore = require('../lib/utils').indentBefore; +var updateIndent = require('../lib/utils').updateIndent; +var updateState = require('../lib/utils').updateState; - //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); - }); - } +function findConstructorIndex(object) { + var classElements = object.body && object.body.body || []; + for (var i = 0; i < classElements.length; i++) { + if (classElements[i].type === Syntax.MethodDefinition && + classElements[i].key.name === 'constructor') { + return i; + } + } + return -1; +} - //Call the factory with the right dependencies. - if (typeof factory === 'function') { - result = factory.apply(module.exports, deps); - } else { - result = factory; - } +var _mungedSymbolMaps = {}; +function getMungedName(scopeName, name, minify) { + if (minify) { + if (!_mungedSymbolMaps[scopeName]) { + _mungedSymbolMaps[scopeName] = { + symbolMap: {}, + identifierUUIDCounter: 0 + }; + } - if (result !== undefined) { - m.exports = result; - if (id) { - loaderCache[id] = m.exports; - } - } + var symbolMap = _mungedSymbolMaps[scopeName].symbolMap; + if (!symbolMap[name]) { + symbolMap[name] = + base62.encode(_mungedSymbolMaps[scopeName].identifierUUIDCounter); + _mungedSymbolMaps[scopeName].identifierUUIDCounter++; } + name = symbolMap[name]; + } + return '$' + scopeName + name; +} - stringRequire = function (systemRequire, exports, module, id, relId) { - //Split the ID by a ! so that - var index = id.indexOf('!'), - originalId = id, - prefix, plugin; +function shouldMungeName(scopeName, name, state) { + // only run when @preventMunge is not present in the docblock + if (state.g.preventMunge === undefined) { + var docblock = require('../lib/docblock'); + state.g.preventMunge = docblock.parseAsObject( + docblock.extract(state.g.source)).preventMunge !== undefined; + } + // Starts with only a single underscore (i.e. don't count double-underscores) + return !state.g.preventMunge && scopeName ? /^_(?!_)/.test(name) : false; +} - 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); +function getProtoOfPrototypeVariableName(superVar) { + return superVar + 'ProtoOfPrototype'; +} - plugin = stringRequire(systemRequire, exports, module, prefix, relId); +function getSuperKeyName(superVar) { + return superVar + 'Key'; +} - if (plugin.normalize) { - id = plugin.normalize(id, makeNormalize(relId)); - } else { - //Normalize the ID normally. - id = normalize(id, relId); - } +function getSuperProtoOfPrototypeVariable(superVariableName, indent) { + var string = (indent + + 'var $proto = $superName && $superName.prototype ? ' + + '$superName.prototype : $superName;\n' + ).replace(/\$proto/g, getProtoOfPrototypeVariableName(superVariableName)) + .replace(/\$superName/g, superVariableName); + return string; +} - if (loaderCache[id]) { - return loaderCache[id]; - } else { - plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); - return loaderCache[id]; - } - } - }; +function getInheritanceSetup(superClassToken, className, indent, superName) { + var string = ''; + if (superClassToken) { + string += getStaticMethodsOnConstructorSetup(className, indent, superName); + string += getPrototypeOnConstructorSetup(className, indent, superName); + string += getConstructorPropertySetup(className, indent); + } + return string; +} - //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; - } +function getStaticMethodsOnConstructorSetup(className, indent, superName) { + var string = ( indent + + 'for (var $keyName in $superName) {\n' + indent + + ' if ($superName.hasOwnProperty($keyName)) {\n' + indent + + ' $className[$keyName] = $superName[$keyName];\n' + indent + + ' }\n' + indent + + '}\n') + .replace(/\$className/g, className) + .replace(/\$keyName/g, getSuperKeyName(superName)) + .replace(/\$superName/g, superName); + return string; +} - if (deps && !Array.isArray(deps)) { - factory = deps; - deps = undefined; - } +function getPrototypeOnConstructorSetup(className, indent, superName) { + var string = ( indent + + '$className.prototype = Object.create($protoPrototype);\n') + .replace(/\$protoPrototype/g, getProtoOfPrototypeVariableName(superName)) + .replace(/\$className/g, className); + return string; +} - if (!deps) { - deps = ['require', 'exports', 'module']; - } +function getConstructorPropertySetup(className, indent) { + var string = ( indent + + '$className.prototype.constructor = $className;\n') + .replace(/\$className/g, className); - //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); - } - } + return string; +} - //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]; - } +function getSuperConstructorSetup(superClassToken, indent, superName) { + if (!superClassToken) return ''; + var string = ( '\n' + indent + + ' if ($superName && $superName.prototype) {\n' + indent + + ' $superName.apply(this, arguments);\n' + indent + + ' }\n' + indent) + .replace(/\$superName/g, superName); + return string; +} - if (defineCache[id]) { - runFactory.apply(null, defineCache[id]); - return loaderCache[id]; - } - }; +function getMemberFunctionCall(superVar, propertyName, superArgs) { + var string = ( + '$superPrototype.$propertyName.call($superArguments)') + .replace(/\$superPrototype/g, getProtoOfPrototypeVariableName(superVar)) + .replace(/\$propertyName/g, propertyName) + .replace(/\$superArguments/g, superArgs); + return string; +} - define.amd = {}; +function getCallParams(classElement, state) { + var params = classElement.value.params; + if (!params.length) { + return ''; + } + return state.g.source.substring( + params[0].range[0], + params[params.length - 1].range[1]); +} - return define; +function getSuperArguments(callExpression, state) { + var args = callExpression.arguments; + if (!args.length) { + return 'this'; + } + return 'this, ' + state.g.source.substring( + args[0].range[0], + args[args.length - 1].range[1]); } -module.exports = amdefine; +// The seed is used to generate the name for an anonymous class, +// and this seed should be unique per browser's session. +// The value of the seed looks like this: 1229588505.2969012. +var classIDSeed = Date.now() % (60 * 60 * 1000) + Math.random(); -})(require("__browserify_process"),"/../node_modules/source-map/node_modules/amdefine/amdefine.js") -},{"path":22,"__browserify_process":21}],16:[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. +/** + * Generates a name for an anonymous class. The generated value looks like + * this: "Classkc6pcn_mniza1yvi" + * @param {String} scopeName + * @return {string} the scope name for Anonymous Class */ -if (typeof define !== 'function') { - var define = require('amdefine')(module); +function generateAnonymousClassName(scopeName) { + classIDSeed++; + return 'Class' + + (classIDSeed).toString(36).replace('.', '_') + + (scopeName || ''); } -define(function (require, exports, module) { - var base64 = require('./base64'); +function renderMethods(traverse, object, name, path, state) { + var classElements = object.body && object.body.body || []; - // 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 + move(object.body.range[0] + 1, state); + for (var i = 0; i < classElements.length; i++) { + if (classElements[i].key.name !== 'constructor') { + catchup(classElements[i].range[0], state); - var VLQ_BASE_SHIFT = 5; + var memberName = classElements[i].key.name; + if (shouldMungeName(state.scopeName, memberName, state)) { + memberName = getMungedName( + state.scopeName, + memberName, + state.g.opts.minify + ); + } - // binary: 100000 - var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + var prototypeOrStatic; + if (classElements[i]['static']) { + prototypeOrStatic = ''; + } else { + prototypeOrStatic = 'prototype.'; + } - // binary: 011111 - var VLQ_BASE_MASK = VLQ_BASE - 1; + append(name + '.' + prototypeOrStatic + memberName + ' = ', state); + renderMethod(traverse, classElements[i], null, path, state); + append(';', state); + } + move(classElements[i].range[1], state); + } + if (classElements.length) { + append('\n', state); + } + move(object.range[1], state); +} - // binary: 100000 - var VLQ_CONTINUATION_BIT = VLQ_BASE; +function renderMethod(traverse, method, name, path, state) { + append(name ? 'function ' + name + '(' : 'function(', state); + append(getCallParams(method, state) + ') {', state); + move(method.value.body.range[0] + 1, state); + traverse(method.value.body, path, state); + catchup(method.value.body.range[1] - 1, state); + append('}', state); +} - /** - * 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; - } +function renderSuperClass(traverse, superClass, path, state) { + append('var ' + state.superVar + ' = ', state); + move(superClass.range[0], state); + traverse(superClass, path, state); + catchup(superClass.range[1], state); + append(';\n', state); +} - /** - * 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; +function renderConstructor(traverse, object, name, indent, path, state) { + var classElements = object.body && object.body.body || []; + var constructorIndex = findConstructorIndex(object); + var constructor = constructorIndex === -1 ? + null : + classElements[constructorIndex]; + if (constructor) { + move(constructorIndex === 0 ? + object.body.range[0] + 1 : + classElements[constructorIndex - 1].range[1], state); + catchup(constructor.range[0], state); + renderMethod(traverse, constructor, name, path, state); + append('\n', state); + } else { + if (object.superClass) { + append('\n' + indent, state); + } + append('function ', state); + if (object.id) { + move(object.id.range[0], state); + } + append(name, state); + if (object.id) { + move(object.id.range[1], state); + } + append('(){ ', state); + if (object.body) { + move(object.body.range[0], state); + } + append(getSuperConstructorSetup( + object.superClass, + indent, + state.superVar), state); + append('}\n', state); } +} - /** - * Returns the base 64 VLQ encoded value. - */ - exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; +var superId = 0; +function renderClassBody(traverse, object, path, state) { + var name = object.id ? object.id.name : 'constructor'; + var superClass = object.superClass; + var indent = updateIndent( + indentBefore(object.range[0], state) + ' ', + state); - var vlq = toVLQSigned(aValue); + state = updateState( + state, + { + scopeName: object.id ? object.id.name : + generateAnonymousClassName(state.scopeName), + superVar: superClass ? '__super' + superId++ : '' + }); - 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); + // super class + if (superClass) { + append(indent, state); + renderSuperClass(traverse, superClass, path, state); + append(getSuperProtoOfPrototypeVariable(state.superVar, indent), state); + } - return encoded; - }; + renderConstructor(traverse, object, name, indent, path, state); + append(getInheritanceSetup(superClass, name, indent, state.superVar), state); + renderMethods(traverse, object, name, path, state); +} - /** - * 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); +/** + * @public + */ +function visitClassExpression(traverse, object, path, state) { + var indent = updateIndent( + indentBefore(object.range[0], state) + ' ', + state); + var name = object.id ? object.id.name : 'constructor'; - return { - value: fromVLQSigned(result), - rest: aStr.slice(i) - }; - }; + append('(function() {\n', state); + renderClassBody(traverse, object, path, state); + append(indent + 'return ' + name + ';\n', state); + append(indent.substring(0, indent.length - 2) + '})()', state); + return false +} -}); +visitClassExpression.test = function(object, path, state) { + return object.type === Syntax.ClassExpression; +}; -},{"./base64":23,"amdefine":19}],17:[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 +/** + * @public */ -if (typeof define !== 'function') { - var define = require('amdefine')(module); +function visitClassDeclaration(traverse, object, path, state) { + state.g.indentBy--; + renderClassBody(traverse, object, path, state); + state.g.indentBy++; + return false; } -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.'); - } +visitClassDeclaration.test = function(object, path, state) { + return object.type === Syntax.ClassDeclaration; +}; + + +/** + * @public + */ +function visitSuperCall(traverse, object, path, state) { + if (path[0].type === Syntax.CallExpression) { + append(state.superVar + + '.call(' + getSuperArguments(path[0], state) + ')', state); + move(path[0].range[1], state); + } else if (path[0].type === Syntax.MemberExpression) { + append(getMemberFunctionCall( + state.superVar, + path[0].property.name, + getSuperArguments(path[1], state)), state); + move(path[1].range[1], state); } - exports.getArg = getArg; + return false; +} - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; +visitSuperCall.test = function(object, path, state) { + return state.superVar && object.type === Syntax.Identifier && + object.name === 'super'; +}; - function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; +/** + * @public + */ +function visitPrivateProperty(traverse, object, path, state) { + var type = path[0] ? path[0].type : null; + if (type !== Syntax.Property) { + if (type === Syntax.MemberExpression) { + type = path[0].object ? path[0].object.type : null; + if (type === Syntax.Identifier && + path[0].object.range[0] === object.range[0]) { + // Identifier is a variable that appears "private". + return; + } + } else { + // Other syntax that are neither Property nor MemberExpression. + return; } - return { - scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] - }; } - function join(aRoot, aPath) { - var url; + var oldName = object.name; + var newName = getMungedName( + state.scopeName, + oldName, + state.g.opts.minify + ); + append(newName, state); + move(object.range[1], state); +} - if (aPath.match(urlRegexp)) { - return aPath; - } +visitPrivateProperty.test = function(object, path, state) { + return object.type === Syntax.Identifier && + shouldMungeName(state.scopeName, object.name, state); +}; - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - return aRoot.replace(url.path, '') + aPath; - } - return aRoot.replace(/\/$/, '') + '/' + aPath; - } - exports.join = join; +exports.visitClassDeclaration = visitClassDeclaration; +exports.visitClassExpression = visitClassExpression; +exports.visitSuperCall = visitSuperCall; +exports.visitPrivateProperty = visitPrivateProperty; - /** - * Because behavior goes wacky when you set `__proto__` on objects, 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 - */ - function toSetString(aStr) { - return '$' + aStr; - } - exports.toSetString = toSetString; +})() +},{"../lib/docblock":16,"../lib/utils":18,"base62":1,"esprima":4}],20:[function(require,module,exports){ +(function(){/** + * 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"; - function fromSetString(aStr) { - return aStr.substr(1); - } - exports.fromSetString = fromSetString; +var Syntax = require('esprima').Syntax; - function relative(aRoot, aPath) { - aRoot = aRoot.replace(/\/$/, ''); - return aPath.indexOf(aRoot + '/') === 0 - ? aPath.substr(aRoot.length + 1) - : aPath; - } - exports.relative = relative; +var catchup = require('../lib/utils').catchup; +var append = require('../lib/utils').append; +var move = require('../lib/utils').move; +var getDocblock = require('../lib/utils').getDocblock; -}); +var FALLBACK_TAGS = require('./xjs').knownTags; +var renderXJSExpressionContainer = + require('./xjs').renderXJSExpressionContainer; +var renderXJSLiteral = require('./xjs').renderXJSLiteral; +var quoteAttrName = require('./xjs').quoteAttrName; -},{"amdefine":19}],18:[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 +/** + * 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. */ -if (typeof define !== 'function') { - var define = require('amdefine')(module); -} -define(function (require, exports, module) { - var util = require('./util'); - - /** - * 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 = {}; - } +var JSX_ATTRIBUTE_RENAMES = { + 'class': 'className', + cxName: 'className' +}; - /** - * 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]); +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(',') + ')'; } - return set; - }; + } +}; - /** - * 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[util.toSetString(aStr)] = idx; - }; +function visitReactTag(traverse, object, path, state) { + var jsxObjIdent = getDocblock(state).jsx; - /** - * 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, - util.toSetString(aStr)); - }; + catchup(object.openingElement.range[0], state); - /** - * 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[util.toSetString(aStr)]; - } - throw new Error('"' + aStr + '" is not in the set.'); - }; + if (object.name.namespace) { + throw new Error( + 'Namespace tags are not supported. ReactJSX is not XML.'); + } - /** - * 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); - }; + var isFallbackTag = FALLBACK_TAGS[object.name.name]; + append( + (isFallbackTag ? jsxObjIdent + '.' : '') + (object.name.name) + '(', + state + ); - /** - * 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(); - }; + move(object.name.range[1], state); - exports.ArraySet = ArraySet; + 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) { + append('null', state); + } -},{"./util":17,"amdefine":19}],20:[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) { + // write attributes + object.attributes.forEach(function(attr, index) { + catchup(attr.range[0], state); + if (attr.name.namespace) { + throw new Error( + 'Namespace attributes are not supported. ReactJSX is not XML.'); + } + var name = JSX_ATTRIBUTE_RENAMES[attr.name.name] || attr.name.name; + var isFirst = index === 0; + var isLast = index === object.attributes.length - 1; - /** - * 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]; + if (isFirst) { + append('{', state); } - 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); + + append(quoteAttrName(name), state); + append(':', state); + + if (!attr.value) { + state.g.buffer += 'true'; + state.g.position = attr.name.range[1]; + if (!isLast) { + append(',', state); } - // 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); + } else if (JSX_ATTRIBUTE_TRANSFORMS[attr.name.name]) { + move(attr.value.range[0], state); + append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state); + move(attr.value.range[1], state); + if (!isLast) { + append(',', state); } - // 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]; + } else if (attr.value.type === Syntax.Literal) { + move(attr.value.range[0], state); + renderXJSLiteral(attr.value, isLast, state); + } else { + move(attr.value.range[0], state); + renderXJSExpressionContainer(traverse, attr.value, isLast, path, state); } - } - - /** - * 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":19}],22:[function(require,module,exports){ -(function(process){function filter (xs, fn) { - var res = []; - for (var i = 0; i < xs.length; i++) { - if (fn(xs[i], i, xs)) res.push(xs[i]); + if (isLast) { + append('}', state); } - return res; -} -// 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; 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--; - } - } + catchup(attr.range[1], state); + }); - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } + if (!object.selfClosing) { + catchup(object.openingElement.range[1] - 1, state); + move(object.openingElement.range[1], state); } - return parts; -} + // filter out whitespace + if (childrenToRender.length > 0) { + append(', ', state); -// Regex to split a filename into [*, dir, basename, ext] -// posix version -var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/; + object.children.forEach(function(child) { + if (child.type === Syntax.Literal && !child.value.match(/\S/)) { + return; + } + catchup(child.range[0], state); -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { -var resolvedPath = '', - resolvedAbsolute = false; + var isLast = child === childrenToRender[childrenToRender.length - 1]; -for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) - ? arguments[i] - : process.cwd(); + 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) { + append(',', state); + state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1'); + } + } - // Skip empty and invalid entries - if (typeof path !== 'string' || !path) { - continue; + catchup(child.range[1], state); + }); } - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; + if (object.selfClosing) { + // everything up to /> + catchup(object.openingElement.range[1] - 2, state); + move(object.openingElement.range[1], state); + } else { + // everything up to + catchup(object.closingElement.range[0], state); + move(object.closingElement.range[1], state); + } + + append(')', state); + return false; } -// 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) +visitReactTag.test = function(object, path, state) { + // only run react when react @jsx namespace is specified in docblock + var jsx = getDocblock(state).jsx; + return object.type === Syntax.XJSElement && jsx && jsx.length; +}; -// Normalize the path -resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); +exports.visitReactTag = visitReactTag; - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; +})() +},{"../lib/utils":18,"./xjs":22,"esprima":4}],21:[function(require,module,exports){ +(function(){/** + * 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"; -// path.normalize(path) -// posix version -exports.normalize = function(path) { -var isAbsolute = path.charAt(0) === '/', - trailingSlash = path.slice(-1) === '/'; +var Syntax = require('esprima').Syntax; +var catchup = require('../lib/utils').catchup; +var append = require('../lib/utils').append; +var getDocblock = require('../lib/utils').getDocblock; -// Normalize the path -path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); +/** + * 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) { - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; + var displayName = object.id.name; + catchup(object.init['arguments'][0].range[0] + 1, state); + append("displayName: '" + displayName + "',", state); } - - return (isAbsolute ? '/' : '') + path; +} + +/** + * Will only run on @jsx files for now. + */ +visitReactDisplayName.test = function(object, path, state) { + return object.type === Syntax.VariableDeclarator && !!getDocblock(state).jsx; }; +exports.visitReactDisplayName = visitReactDisplayName; -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - return p && typeof p === 'string'; - }).join('/')); +})() +},{"../lib/utils":18,"esprima":4}],22:[function(require,module,exports){ +(function(){/** + * 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('../lib/utils').append; +var catchup = require('../lib/utils').catchup; +var move = require('../lib/utils').move; +var Syntax = require('esprima').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]+$/, ''); +} -exports.dirname = function(path) { - var dir = splitPathRe.exec(path)[1] || ''; - var isWindows = false; - if (!dir) { - // No dirname - return '.'; - } else if (dir.length === 1 || - (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) { - // It is just a slash or a drive letter with a slash - return dir; - } else { - // It is a full dirname, strip trailing slash - return dir.substring(0, dir.length - 1); - } -}; +// 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); -exports.basename = function(path, ext) { - var f = splitPathRe.exec(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; -}; + if (trimmedChildValue) { + // head whitespace + append(object.value.match(/^[\t ]*/)[0], state); + if (start) { + append(start, state); + } + var trimmedChildValueWithSpace = trimWithSingleSpace(object.value); -exports.extname = function(path) { - return splitPathRe.exec(path)[3] || ''; -}; + /** + */ + var initialLines = trimmedChildValue.split(/\r\n|\n|\r/); -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); + var lines = initialLines.filter(function(line) { + return safeTrim(line).length > 0; + }); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } + var hasInitialNewLine = initialLines[0] !== lines[0]; + var hasFinalNewLine = + initialLines[initialLines.length - 1] !== lines[lines.length - 1]; - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; + 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 = ''; + + if (ii === 0) { + if (hasInitialNewLine) { + preString = ' '; + leading = '\n'; + } + 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 = ' '; + } + } else { + leading = line.match(/^[ \t]*/)[0]; + } + 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); + } - if (start > end) return []; - return arr.slice(start, end - start + 1); + // add comma before trailing whitespace + if (!isLast) { + append(',', state); } - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); + // tail whitespace + append(object.value.match(/[ \t]*$/)[0], state); + move(object.range[1], state); +} - 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; - } +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); } - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); + // 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; +} - outputParts = outputParts.concat(toParts.slice(samePartsLength)); +exports.knownTags = knownTags; +exports.renderXJSExpressionContainer = renderXJSExpressionContainer; +exports.renderXJSLiteral = renderXJSLiteral; +exports.quoteAttrName = quoteAttrName; - return outputParts.join('/'); -}; +})() +},{"../lib/utils":18,"esprima":4}],23:[function(require,module,exports){ +(function(){/*global exports:true*/ +var classes = require('./transforms/classes'); +var react = require('./transforms/react'); +var reactDisplayName = require('./transforms/reactDisplayName'); -})(require("__browserify_process")) -},{"__browserify_process":21}],23:[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 +/** + * Map from transformName => orderedListOfVisitors. */ -if (typeof define !== 'function') { - var define = require('amdefine')(module); -} -define(function (require, exports, module) { - - var charToIntMap = {}; - var intToCharMap = {}; +var transformVisitors = { + 'es6-classes': [ + classes.visitClassExpression, + classes.visitClassDeclaration, + classes.visitSuperCall, + classes.visitPrivateProperty + ] +}; - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - .split('') - .forEach(function (ch, index) { - charToIntMap[ch] = index; - intToCharMap[index] = ch; - }); +transformVisitors.react = transformVisitors[ + "es6-classes" +].concat([ + react.visitReactTag, + reactDisplayName.visitReactDisplayName +]); - /** - * 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); - }; +/** + * Specifies the order in which each transform should run. + */ +var transformRunOrder = [ + 'es6-classes', + 'react' +]; - /** - * Decode a single base 64 digit to an integer. - */ - exports.decode = function base64_decode(aChar) { - if (aChar in charToIntMap) { - return charToIntMap[aChar]; +/** + * 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]]); } - throw new TypeError("Not a valid base 64 digit: " + aChar); - }; + } + return ret; +} -}); +exports.getVisitorsList = getVisitorsList; +exports.transformVisitors = transformVisitors; -},{"amdefine":19}]},{},[1])(1) +})() +},{"./transforms/classes":19,"./transforms/react":20,"./transforms/reactDisplayName":21}]},{},[15])(15) }); ; \ No newline at end of file diff --git a/labs/architecture-examples/react/bower_components/react/bower.json b/labs/architecture-examples/react/bower_components/react/bower.json new file mode 100644 index 0000000000..294a300341 --- /dev/null +++ b/labs/architecture-examples/react/bower_components/react/bower.json @@ -0,0 +1,5 @@ +{ + "name": "react", + "version": "0.4.0", + "main": "react.js" +} \ No newline at end of file diff --git a/labs/architecture-examples/react/bower_components/react/react.js b/labs/architecture-examples/react/bower_components/react/react.js index 8c374be3ef..c58ec133f0 100644 --- a/labs/architecture-examples/react/bower_components/react/react.js +++ b/labs/architecture-examples/react/bower_components/react/react.js @@ -1,5 +1,5 @@ /** - * React v0.3.2 + * React v0.4.0 */ (function(e){if("function"==typeof bootstrap)bootstrap("react",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeReact=e}else"undefined"!=typeof window?window.React=e():global.React=e()})(function(){var define,ses,bootstrap,module,exports; return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s createMarkupForStyles({width: '200px', height: 0}) + * "width:200px;height:0;" + * + * Undefined values are ignored so that declarative programming is easier. + * + * @param {object} styles + * @return {?string} */ - DEFINE_MANY: null, + 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; + }, + /** - * These methods are overriding the base ReactCompositeComponent class. + * 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 */ - OVERRIDE_BASE: null -}); + 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":2,"./dangerousStyleValue":63,"./escapeTextForBrowser":65,"./hyphenate":73,"./memoizeStringOnly":80}],4:[function(require,module,exports){ /** - * Composite components are higher-level components that compose other composite - * or native components. + * Copyright 2013 Facebook, Inc. * - * To create a new type of `ReactCompositeComponent`, pass a specification of - * your new class to `React.createClass`. The only requirement of your class - * specification is that you implement a `render` method. + * 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 * - * var MyComponent = React.createClass({ - * render: function() { - * return
Hello World
; - * } - * }); + * http://www.apache.org/licenses/LICENSE-2.0 * - * The class specification supports a specific protocol of methods that have - * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for - * more the comprehensive protocol. Any other properties and methods in the - * class specification will available on the prototype. + * 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. * - * @interface ReactCompositeComponentInterface + * @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 ReactCompositeComponentInterface = { +var CallbackRegistry = { /** - * An array of Mixin objects to include when defining your component. + * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. * - * @type {array} - * @optional + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {?function} listener The callback to store. */ - mixins: SpecPolicy.DEFINE_MANY, + putListener: function(id, registrationName, listener) { + var bankForRegistrationName = + listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[id] = listener; + }, /** - * Definition of props for this component. - * - * @type {array} - * @optional + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. */ - props: SpecPolicy.DEFINE_ONCE, - - - - // ==== Definition methods ==== + getListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + return bankForRegistrationName && bankForRegistrationName[id]; + }, /** - * Invoked once before the component is mounted. The return value will be used - * as the initial value of `this.state`. - * - * getInitialState: function() { - * return { - * isOn: false, - * fooBaz: new BazFoo() - * } - * } + * Deletes a listener from the registration bank. * - * @return {object} - * @optional + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). */ - getInitialState: SpecPolicy.DEFINE_ONCE, + deleteListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + if (bankForRegistrationName) { + delete bankForRegistrationName[id]; + } + }, /** - * Uses props from `this.props` and state from `this.state` to render the - * structure of the component. - * - * No guarantees are made about when or how often this method is invoked, so - * it must not have side effects. - * - * render: function() { - * var name = this.props.name; - * return
Hello, {name}!
; - * } + * Deletes all listeners for the DOM element with the supplied ID. * - * @return {ReactComponent} - * @nosideeffects - * @required + * @param {string} id ID of the DOM element. */ - render: SpecPolicy.DEFINE_ONCE, + deleteAllListeners: function(id) { + for (var registrationName in listenerBank) { + delete listenerBank[registrationName][id]; + } + }, + /** + * This is needed for tests only. Do not use! + */ + __purge: function() { + listenerBank = {}; + } +}; - // ==== Delegate methods ==== +module.exports = CallbackRegistry; - /** - * Invoked when the component is initially created and about to be mounted. - * This may have side effects, but any external subscriptions or data created - * by this method must be cleaned up in `componentWillUnmount`. - * - * @optional - */ - componentWillMount: SpecPolicy.DEFINE_MANY, +},{}],5:[function(require,module,exports){ +(function(){/** + * 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 + */ - /** - * Invoked when the component has been mounted and has a DOM representation. - * However, there is no guarantee that the DOM node is in the document. - * - * Use this as an opportunity to operate on the DOM when the component has - * been mounted (initialized and rendered) for the first time. - * - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidMount: SpecPolicy.DEFINE_MANY, +"use strict"; - /** - * Invoked before the component receives new props. - * - * Use this as an opportunity to react to a prop transition by updating the - * state using `this.setState`. Current props are accessed via `this.props`. - * - * componentWillReceiveProps: function(nextProps) { - * this.setState({ - * likesIncreasing: nextProps.likeCount > this.props.likeCount - * }); - * } - * - * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop - * transition may cause a state change, but the opposite is not true. If you - * need it, you are probably looking for `componentWillUpdate`. - * - * @param {object} nextProps - * @optional - */ - componentWillReceiveProps: SpecPolicy.DEFINE_MANY, +var EventConstants = require("./EventConstants"); +var EventPluginHub = require("./EventPluginHub"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var SyntheticEvent = require("./SyntheticEvent"); - /** - * Invoked while deciding if the component should be updated as a result of - * receiving new props and state. - * - * Use this as an opportunity to `return false` when you're certain that the - * transition to the new props and state will not require a component update. - * - * shouldComponentUpdate: function(nextProps, nextState) { - * return !equal(nextProps, this.props) || !equal(nextState, this.state); - * } - * - * @param {object} nextProps - * @param {?object} nextState - * @return {boolean} True if the component should update. - * @optional - */ - shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, +var isEventSupported = require("./isEventSupported"); +var keyOf = require("./keyOf"); - /** - * Invoked when the component is about to update due to a transition from - * `this.props` and `this.state` to `nextProps` and `nextState`. - * - * Use this as an opportunity to perform preparation before an update occurs. - * - * NOTE: You **cannot** use `this.setState()` in this method. - * - * @param {object} nextProps - * @param {?object} nextState - * @param {ReactReconcileTransaction} transaction - * @optional - */ - componentWillUpdate: SpecPolicy.DEFINE_MANY, +var topLevelTypes = EventConstants.topLevelTypes; - /** - * Invoked when the component's DOM representation has been updated. - * - * Use this as an opportunity to operate on the DOM when the component has - * been updated. - * - * @param {object} prevProps - * @param {?object} prevState - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidUpdate: SpecPolicy.DEFINE_MANY, +var eventTypes = { + change: { + phasedRegistrationNames: { + bubbled: keyOf({onChange: null}), + captured: keyOf({onChangeCapture: null}) + } + } +}; - /** - * Invoked when the component is about to be removed from its parent and have - * its DOM representation destroyed. - * - * Use this as an opportunity to deallocate any external resources. - * - * NOTE: There is no `componentDidUnmount` since your component will have been - * destroyed by that point. - * - * @optional - */ - componentWillUnmount: SpecPolicy.DEFINE_MANY, +/** + * 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') + ); +} - // ==== Advanced methods ==== +var doesChangeEventBubble = false; +if (ExecutionEnvironment.canUseDOM) { + // See `handleChange` comment below + doesChangeEventBubble = isEventSupported('change') && ( + !('documentMode' in document) || document.documentMode > 8 + ); +} - /** - * Updates the component's currently mounted DOM representation. - * - * By default, this implements React's rendering and reconciliation algorithm. - * Sophisticated clients may wish to override this. - * - * @param {ReactReconcileTransaction} transaction - * @internal - * @overridable - */ - updateComponent: SpecPolicy.OVERRIDE_BASE +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 + ); +} + +/** + * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + */ +var supportedInputTypes = { + 'color': true, + 'date': true, + 'datetime': true, + 'datetime-local': true, + 'email': true, + 'month': true, + 'number': true, + 'password': true, + 'range': true, + 'search': true, + 'tel': true, + 'text': true, + 'time': true, + 'url': true, + 'week': true }; +function shouldUseInputEvent(elem) { + return ( + (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type]) || + elem.nodeName === 'TEXTAREA' + ); +} + /** - * Mapping from class specification keys to special processing functions. - * - * Although these are declared in the specification when defining classes - * using `React.createClass`, they will not be on the component's prototype. + * (For old IE.) Replacement getter/setter for the `value` property that gets + * set on the active element. */ -var RESERVED_SPEC_KEYS = { - displayName: function(Constructor, displayName) { - Constructor.displayName = displayName; +var newValueProp = { + get: function() { + return activeElementValueProp.get.call(this); }, - mixins: function(Constructor, mixins) { - if (mixins) { - for (var i = 0; i < mixins.length; i++) { - mixSpecIntoComponent(Constructor, mixins[i]); - } - } - }, - props: function(Constructor, props) { - Constructor.propDeclarations = props; + set: function(val) { + // Cast to a string so we can do equality checks. + activeElementValue = '' + val; + activeElementValueProp.set.call(this, val); } }; /** - * Custom version of `mixInto` which handles policy validation and reserved - * specification keys when building `ReactCompositeComponent` classses. + * (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 mixSpecIntoComponent(Constructor, spec) { - var proto = Constructor.prototype; - for (var name in spec) { - if (!spec.hasOwnProperty(name)) { - continue; - } - var property = spec[name]; - var specPolicy = ReactCompositeComponentInterface[name]; +function startWatchingForValueChange(target, targetID) { + activeElement = target; + activeElementID = targetID; + activeElementValue = target.value; + activeElementValueProp = Object.getOwnPropertyDescriptor( + target.constructor.prototype, + 'value' + ); - // Disallow overriding of base class methods unless explicitly allowed. - if (ReactCompositeComponentMixin.hasOwnProperty(name)) { - invariant( - specPolicy === SpecPolicy.OVERRIDE_BASE, - 'ReactCompositeComponentInterface: You are attempting to override ' + - '`%s` from your class specification. Ensure that your method names ' + - 'do not overlap with React methods.', - name - ); - } + Object.defineProperty(activeElement, 'value', newValueProp); + activeElement.attachEvent('onpropertychange', handlePropertyChange); +} - // Disallow using `React.autoBind` on internal methods. - if (specPolicy != null) { - invariant( - !property || !property.__reactAutoBind, - 'ReactCompositeComponentInterface: You are attempting to use ' + - '`React.autoBind` on `%s`, a method that is internal to React.' + - 'Internal methods are called with the component as the context.', - name - ); - } +/** + * (For old IE.) Removes the event listeners from the currently-tracked element, + * if any exists. + */ +function stopWatchingForValueChange() { + if (!activeElement) { + return; + } - // Disallow defining methods more than once unless explicitly allowed. - if (proto.hasOwnProperty(name)) { - invariant( - specPolicy === SpecPolicy.DEFINE_MANY, - 'ReactCompositeComponentInterface: You are attempting to define ' + - '`%s` on your component more than once. This conflict may be due ' + - 'to a mixin.', - name - ); - } + // delete restores the original property definition + delete activeElement.value; + activeElement.detachEvent('onpropertychange', handlePropertyChange); - if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { - RESERVED_SPEC_KEYS[name](Constructor, property); - } else if (property && property.__reactAutoBind) { - if (!proto.__reactAutoBindMap) { - proto.__reactAutoBindMap = {}; - } - proto.__reactAutoBindMap[name] = property.__reactAutoBind; - } else if (proto.hasOwnProperty(name)) { - // For methods which are defined more than once, call the existing methods - // before calling the new property. - proto[name] = createChainedFunction(proto[name], property); - } else { - proto[name] = property; + 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; } } } + /** - * Creates a function that invokes two functions and ignores their return vales. - * - * @param {function} one Function to invoke first. - * @param {function} two Function to invoke second. - * @return {function} Function that invokes the two argument functions. - * @private + * SECTION: handle `click` event */ -function createChainedFunction(one, two) { - return function chainedFunction(a, b, c, d, e, tooMany) { - invariant( - typeof tooMany === 'undefined', - 'Chained function can only take a maximum of 5 arguments.' - ); - one.call(this, a, b, c, d, e); - two.call(this, a, b, c, d, e); - }; +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; + } } /** - * `ReactCompositeComponent` maintains an auxiliary life cycle state in - * `this._compositeLifeCycleState` (which can be null). + * 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. * - * This is different from the life cycle state maintained by `ReactComponent` in - * `this._lifeCycleState`. + * Supported elements are: + * - input (see `supportedInputTypes`) + * - textarea + * - select */ -var CompositeLifeCycle = keyMirror({ +var ChangeEventPlugin = { + + eventTypes: eventTypes, + /** - * Components in the process of being mounted respond to state changes - * differently. + * @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} */ - MOUNTING: null, - /** - * Components in the process of being unmounted are guarded against state - * changes. - */ - UNMOUNTING: null, - /** - * Components that are mounted and receiving new props respond to state - * changes differently. - */ - RECEIVING_PROPS: null, - /** - * Components that are mounted and receiving new state are guarded against - * additional state changes. - */ - RECEIVING_STATE: null -}); + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { -/** - * @lends {ReactCompositeComponent.prototype} + var getTargetIDFunc, handleEventFunc; + if (shouldUseChangeEvent(topLevelTarget)) { + if (doesChangeEventBubble) { + getTargetIDFunc = getTargetIDForChangeEvent; + } else { + handleEventFunc = handleEventsForChangeEventIE8; + } + } else if (shouldUseInputEvent(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":13,"./EventPluginHub":15,"./EventPropagators":18,"./ExecutionEnvironment":19,"./SyntheticEvent":50,"./isEventSupported":76,"./keyOf":79}],6:[function(require,module,exports){ +(function(){/** + * 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 */ -var ReactCompositeComponentMixin = { - /** - * Base constructor for all composite component. - * - * @param {?object} initialProps - * @param {*} children - * @final - * @internal - */ - construct: function(initialProps, children) { - ReactComponent.Mixin.construct.call(this, initialProps, children); - this.state = null; - this._pendingState = null; - this._compositeLifeCycleState = null; - }, +// Empty blocks improve readability so disable that warning +// jshint -W035 - /** - * Initializes the component, renders markup, and registers event listeners. - * - * @param {string} rootID DOM ID of the root node. - * @param {ReactReconcileTransaction} transaction - * @return {?string} Rendered markup to be inserted into the DOM. - * @final - * @internal - */ - mountComponent: function(rootID, transaction) { - ReactComponent.Mixin.mountComponent.call(this, rootID, transaction); +"use strict"; - // Unset `this._lifeCycleState` until after this method is finished. - this._lifeCycleState = ReactComponent.LifeCycle.UNMOUNTED; - this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING; +var Danger = require("./Danger"); - if (this.constructor.propDeclarations) { - this._assertValidProps(this.props); - } +var insertNodeAt = require("./insertNodeAt"); +var keyOf = require("./keyOf"); +var throwIf = require("./throwIf"); - if (this.__reactAutoBindMap) { - this._bindAutoBindMethods(); +var NON_INCREASING_OPERATIONS; +if (true) { + NON_INCREASING_OPERATIONS = + 'DOM child management operations must be provided in order ' + + 'of increasing destination index. This is likely an issue with ' + + 'the core framework.'; +} + +var MOVE_NODE_AT_ORIG_INDEX = keyOf({moveFrom: null}); +var INSERT_MARKUP = keyOf({insertMarkup: null}); +var REMOVE_AT = keyOf({removeAt: null}); + +/** + * In order to carry out movement of DOM nodes without knowing their IDs, we + * have to first store knowledge about nodes' original indices before beginning + * to carry out the sequence of operations. Once we begin the sequence, the DOM + * indices in future instructions are no longer valid. + * + * @param {Element} parent Parent DOM node. + * @param {Object} childOperations Description of child operations. + * @return {Array?} Sparse array containing elements by their current index in + * the DOM. + */ +var _getNodesByOriginalIndex = function(parent, childOperations) { + var nodesByOriginalIndex; // Sparse array. + var childOperation; + var origIndex; + for (var i = 0; i < childOperations.length; i++) { + childOperation = childOperations[i]; + if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { + nodesByOriginalIndex = nodesByOriginalIndex || []; + origIndex = childOperation.moveFrom; + nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; + } else if (REMOVE_AT in childOperation) { + nodesByOriginalIndex = nodesByOriginalIndex || []; + origIndex = childOperation.removeAt; + nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; } + } + return nodesByOriginalIndex; +}; - this.state = this.getInitialState ? this.getInitialState() : null; - this._pendingState = null; +/** + * Removes DOM elements from their parent, or moved. + * @param {Element} parent Parent DOM node. + * @param {Array} nodesByOriginalIndex Child nodes by their original index + * (potentially sparse.) + */ +var _removeChildrenByOriginalIndex = function(parent, nodesByOriginalIndex) { + for (var j = 0; j < nodesByOriginalIndex.length; j++) { + var nodeToRemove = nodesByOriginalIndex[j]; + if (nodeToRemove) { // We used a sparse array. + parent.removeChild(nodesByOriginalIndex[j]); + } + } +}; - if (this.componentWillMount) { - this.componentWillMount(); - // When mounting, calls to `setState` by `componentWillMount` will set - // `this._pendingState` without triggering a re-render. - if (this._pendingState) { - this.state = this._pendingState; - this._pendingState = null; +/** + * Once all nodes that will be removed or moved - are removed from the parent + * node, we can begin the process of placing nodes into their final locations. + * We must perform all operations in the order of the final DOM index - + * otherwise, we couldn't count on the fact that an insertion at index X, will + * remain at index X. This will iterate through the child operations, adding + * content where needed, skip over removals (they've already been removed) and + * insert "moved" Elements that were previously removed. The "moved" elements + * are only temporarily removed from the parent, so that index calculations can + * be manageable and perform well in the cases that matter. + */ +var _placeNodesAtDestination = + function(parent, childOperations, nodesByOriginalIndex) { + var origNode; + var finalIndex; + var lastFinalIndex = -1; + var childOperation; + for (var k = 0; k < childOperations.length; k++) { + childOperation = childOperations[k]; + if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { + origNode = nodesByOriginalIndex[childOperation.moveFrom]; + finalIndex = childOperation.finalIndex; + insertNodeAt(parent, origNode, finalIndex); + if (true) { + throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); + lastFinalIndex = finalIndex; + } + } else if (REMOVE_AT in childOperation) { + } else if (INSERT_MARKUP in childOperation) { + finalIndex = childOperation.finalIndex; + var markup = childOperation.insertMarkup; + Danger.dangerouslyInsertMarkupAt(parent, markup, finalIndex); + if (true) { + throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); + lastFinalIndex = finalIndex; + } } } + }; - if (this.componentDidMount) { - transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount); - } +var manageChildren = function(parent, childOperations) { + var nodesByOriginalIndex = _getNodesByOriginalIndex(parent, childOperations); + if (nodesByOriginalIndex) { + _removeChildrenByOriginalIndex(parent, nodesByOriginalIndex); + } + _placeNodesAtDestination(parent, childOperations, nodesByOriginalIndex); +}; - this._renderedComponent = this._renderValidatedComponent(); +/** + * Also reexport all of the dangerous functions. It helps to have all dangerous + * functions located in a single module `Danger`. + */ +var DOMChildrenOperations = { + dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + manageChildren: manageChildren +}; - // Done with mounting, `setState` will now trigger UI changes. - this._compositeLifeCycleState = null; - this._lifeCycleState = ReactComponent.LifeCycle.MOUNTED; +module.exports = DOMChildrenOperations; - return this._renderedComponent.mountComponent(rootID, transaction); - }, +})() +},{"./Danger":9,"./insertNodeAt":74,"./keyOf":79,"./throwIf":86}],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 DOMProperty + * @typechecks static-only + */ + +/*jslint bitwise: true */ + +"use strict"; + +var invariant = require("./invariant"); +var DOMPropertyInjection = { /** - * Releases any resources allocated by `mountComponent`. + * 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_BOOLEAN_VALUE: 0x4, + HAS_SIDE_EFFECTS: 0x8, + + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: * - * @final - * @internal + * 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. */ - unmountComponent: function() { - this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING; - if (this.componentWillUnmount) { - this.componentWillUnmount(); + 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 + ); } - this._compositeLifeCycleState = null; - ReactComponent.Mixin.unmountComponent.call(this); - this._renderedComponent.unmountComponent(); - this._renderedComponent = null; + for (var propName in Properties) { + 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 + ); - if (this.refs) { - this.refs = null; - } + DOMProperty.isStandardName[propName] = true; - // Some existing components rely on this.props even after they've been - // destroyed (in event handlers). - // TODO: this.props = null; - // TODO: this.state = null; - }, + DOMProperty.getAttributeName[propName] = + DOMAttributeNames[propName] || propName.toLowerCase(); - /** - * Updates the rendered DOM nodes given a new set of props. - * - * @param {object} nextProps Next set of properties. - * @param {ReactReconcileTransaction} transaction - * @final - * @internal - */ - receiveProps: function(nextProps, transaction) { - if (this.constructor.propDeclarations) { - this._assertValidProps(nextProps); - } - ReactComponent.Mixin.receiveProps.call(this, nextProps, transaction); + DOMProperty.getPropertyName[propName] = + DOMPropertyNames[propName] || propName; + + var mutationMethod = DOMMutationMethods[propName]; + if (mutationMethod) { + DOMProperty.getMutationMethod[propName] = mutationMethod; + } - this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS; - if (this.componentWillReceiveProps) { - this.componentWillReceiveProps(nextProps, transaction); + var propConfig = Properties[propName]; + DOMProperty.mustUseAttribute[propName] = + propConfig & DOMPropertyInjection.MUST_USE_ATTRIBUTE; + DOMProperty.mustUseProperty[propName] = + propConfig & DOMPropertyInjection.MUST_USE_PROPERTY; + DOMProperty.hasBooleanValue[propName] = + propConfig & DOMPropertyInjection.HAS_BOOLEAN_VALUE; + DOMProperty.hasSideEffects[propName] = + propConfig & DOMPropertyInjection.HAS_SIDE_EFFECTS; + + invariant( + !DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName], + 'DOMProperty: Cannot use require using both attribute and property: %s', + propName + ); + invariant( + DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName], + 'DOMProperty: Properties that have side effects must use property: %s', + propName + ); } - this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; - // When receiving props, calls to `setState` by `componentWillReceiveProps` - // will set `this._pendingState` without triggering a re-render. - var nextState = this._pendingState || this.state; - this._pendingState = null; - this._receivePropsAndState(nextProps, nextState, transaction); - this._compositeLifeCycleState = null; - }, + } +}; +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 = { /** - * Sets a subset of the state. Always use this or `replaceState` to mutate - * state. You should treat `this.state` as immutable. - * - * There is no guarantee that `this.state` will be immediately updated, so - * accessing `this.state` after calling this method may return the old value. - * - * @param {object} partialState Next partial state to be merged with state. - * @final - * @protected + * Checks whether a property name is a standard property. + * @type {Object} */ - setState: function(partialState) { - // Merge with `_pendingState` if it exists, otherwise with existing state. - this.replaceState(merge(this._pendingState || this.state, partialState)); - }, + isStandardName: {}, /** - * Replaces all of the state. Always use this or `setState` to mutate state. - * You should treat `this.state` as immutable. - * - * There is no guarantee that `this.state` will be immediately updated, so - * accessing `this.state` after calling this method may return the old value. - * - * @param {object} completeState Next state. - * @final - * @protected + * Mapping from normalized names to attribute names that differ. Attribute + * names are used when rendering markup or with `*Attribute()`. + * @type {Object} */ - replaceState: function(completeState) { - var compositeLifeCycleState = this._compositeLifeCycleState; - invariant( - this._lifeCycleState === ReactComponent.LifeCycle.MOUNTED || - compositeLifeCycleState === CompositeLifeCycle.MOUNTING, - 'replaceState(...): Can only update a mounted (or mounting) component.' - ); - invariant( - compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && - compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, - 'replaceState(...): Cannot update while unmounting component or during ' + - 'an existing state transition (such as within `render`).' - ); - - this._pendingState = completeState; - - // Do not trigger a state transition if we are in the middle of mounting or - // receiving props because both of those will already be doing this. - if (compositeLifeCycleState !== CompositeLifeCycle.MOUNTING && - compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_PROPS) { - this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; - - var nextState = this._pendingState; - this._pendingState = null; - - var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); - transaction.perform( - this._receivePropsAndState, - this, - this.props, - nextState, - transaction - ); - ReactComponent.ReactReconcileTransaction.release(transaction); - - this._compositeLifeCycleState = null; - } - }, + getAttributeName: {}, /** - * Receives next props and next state, and negotiates whether or not the - * component should update as a result. - * - * @param {object} nextProps Next object to set as props. - * @param {?object} nextState Next object to set as state. - * @param {ReactReconcileTransaction} transaction - * @private + * Mapping from normalized names to properties on DOM node instances. + * (This includes properties that mutate due to external factors.) + * @type {Object} */ - _receivePropsAndState: function(nextProps, nextState, transaction) { - if (!this.shouldComponentUpdate || - this.shouldComponentUpdate(nextProps, nextState)) { - // Will set `this.props` and `this.state`. - this._performComponentUpdate(nextProps, nextState, transaction); - } else { - // If it's determined that a component should not update, we still want - // to set props and state. - this.props = nextProps; - this.state = nextState; - } - }, + getPropertyName: {}, /** - * Merges new props and state, notifies delegate methods of update and - * performs update. - * - * @param {object} nextProps Next object to set as properties. - * @param {?object} nextState Next object to set as state. - * @param {ReactReconcileTransaction} transaction - * @private + * Mapping from normalized names to mutation methods. This will only exist if + * mutation cannot be set simply by the property or `setAttribute()`. + * @type {Object} */ - _performComponentUpdate: function(nextProps, nextState, transaction) { - var prevProps = this.props; - var prevState = this.state; - - if (this.componentWillUpdate) { - this.componentWillUpdate(nextProps, nextState, transaction); - } - - this.props = nextProps; - this.state = nextState; - - this.updateComponent(transaction); + getMutationMethod: {}, - if (this.componentDidUpdate) { - transaction.getReactOnDOMReady().enqueue( - this, - this.componentDidUpdate.bind(this, prevProps, prevState) - ); - } - }, + /** + * Whether the property must be accessed and mutated as an object property. + * @type {Object} + */ + mustUseAttribute: {}, /** - * Updates the component's currently mounted DOM representation. - * - * By default, this implements React's rendering and reconciliation algorithm. - * Sophisticated clients may wish to override this. - * - * @param {ReactReconcileTransaction} transaction - * @internal - * @overridable + * Whether the property must be accessed and mutated using `*Attribute()`. + * (This includes anything that fails ` in `.) + * @type {Object} */ - updateComponent: function(transaction) { - var currentComponent = this._renderedComponent; - var nextComponent = this._renderValidatedComponent(); - if (currentComponent.constructor === nextComponent.constructor) { - if (!nextComponent.props.isStatic) { - currentComponent.receiveProps(nextComponent.props, transaction); - } - } else { - // These two IDs are actually the same! But nothing should rely on that. - var thisID = this._rootNodeID; - var currentComponentID = currentComponent._rootNodeID; - currentComponent.unmountComponent(); - var nextMarkup = nextComponent.mountComponent(thisID, transaction); - ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( - currentComponentID, - nextMarkup - ); - this._renderedComponent = nextComponent; - } - }, + mustUseProperty: {}, /** - * Forces an update. This should only be invoked when it is known with - * certainty that we are **not** in a DOM transaction. - * - * You may want to call this when you know that some deeper aspect of the - * component's state has changed but `setState` was not called. - * - * This will not invoke `shouldUpdateComponent`, but it will invoke - * `componentWillUpdate` and `componentDidUpdate`. - * - * @final - * @protected + * Whether the property should be removed when set to a falsey value. + * @type {Object} */ - forceUpdate: function() { - var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); - transaction.perform( - this._performComponentUpdate, - this, - this.props, - this.state, - transaction - ); - ReactComponent.ReactReconcileTransaction.release(transaction); - }, + hasBooleanValue: {}, /** - * @private + * 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} */ - _renderValidatedComponent: function() { - ReactCurrentOwner.current = this; - var renderedComponent = this.render(); - ReactCurrentOwner.current = null; - invariant( - ReactComponent.isValidComponent(renderedComponent), - '%s.render(): A valid ReactComponent must be returned.', - this.constructor.displayName || 'ReactCompositeComponent' - ); - return renderedComponent; - }, + hasSideEffects: {}, /** - * @param {object} props - * @private + * All of the isCustomAttribute() functions that have been injected. */ - _assertValidProps: function(props) { - var propDeclarations = this.constructor.propDeclarations; - var componentName = this.constructor.displayName; - for (var propName in propDeclarations) { - var checkProp = propDeclarations[propName]; - if (checkProp) { - checkProp(props, propName, componentName); - } - } - }, + _isCustomAttributeFunctions: [], /** - * @private + * Checks whether a property name is a custom attribute. + * @method */ - _bindAutoBindMethods: function() { - for (var autoBindKey in this.__reactAutoBindMap) { - if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { - continue; + isCustomAttribute: function(attributeName) { + return DOMProperty._isCustomAttributeFunctions.some( + function(isCustomAttributeFn) { + return isCustomAttributeFn.call(null, attributeName); } - var method = this.__reactAutoBindMap[autoBindKey]; - this[autoBindKey] = this._bindAutoBindMethod(method); - } + ); }, /** - * Binds a method to the component. + * 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. * - * @param {function} method Method to be bound. - * @private - */ - _bindAutoBindMethod: function(method) { - var component = this; - var hasWarned = false; - function autoBound(a, b, c, d, e, tooMany) { - invariant( - typeof tooMany === 'undefined', - 'React.autoBind(...): Methods can only take a maximum of 5 arguments.' - ); - if (component._lifeCycleState === ReactComponent.LifeCycle.MOUNTED) { - return method.call(component, a, b, c, d, e); - } else if (!hasWarned) { - hasWarned = true; - if (true) { - console.warn( - 'React.autoBind(...): Attempted to invoke an auto-bound method ' + - 'on an unmounted instance of `%s`. You either have a memory leak ' + - 'or an event handler that is being run after unmounting.', - component.constructor.displayName || 'ReactCompositeComponent' - ); - } - } + * 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 = {}; } - return autoBound; - } + if (!(prop in nodeDefaults)) { + testElement = document.createElement(nodeName); + nodeDefaults[prop] = testElement[prop]; + } + return nodeDefaults[prop]; + }, + injection: DOMPropertyInjection }; -var ReactCompositeComponentBase = function() {}; -mixInto(ReactCompositeComponentBase, ReactComponent.Mixin); -mixInto(ReactCompositeComponentBase, ReactOwner.Mixin); -mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin); -mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin); +module.exports = DOMProperty; +},{"./invariant":75}],8:[function(require,module,exports){ /** - * Module for creating composite components. + * Copyright 2013 Facebook, Inc. * - * @class ReactCompositeComponent - * @extends ReactComponent - * @extends ReactOwner - * @extends ReactPropTransferer - */ -var ReactCompositeComponent = { + * 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 + */ - LifeCycle: CompositeLifeCycle, +"use strict"; - Base: ReactCompositeComponentBase, +var DOMProperty = require("./DOMProperty"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { + return escapeTextForBrowser(name) + '="'; +}); + +/** + * Operations for dealing with DOM properties. + */ +var DOMPropertyOperations = { /** - * Creates a composite component class given a class specification. + * Creates markup for a property. * - * @param {object} spec Class specification (which must define `render`). - * @return {function} Component constructor function. - * @public + * @param {string} name + * @param {*} value + * @return {?string} Markup string, or null if the property was invalid. */ - createClass: function(spec) { - var Constructor = function(initialProps, children) { - this.construct(initialProps, children); - }; - Constructor.prototype = new ReactCompositeComponentBase(); - Constructor.prototype.constructor = Constructor; - mixSpecIntoComponent(Constructor, spec); - invariant( - Constructor.prototype.render, - 'createClass(...): Class specification must implement a `render` method.' - ); - - var ConvenienceConstructor = function(props, children) { - return new Constructor(props, children); - }; - ConvenienceConstructor.componentConstructor = Constructor; - ConvenienceConstructor.originalSpec = spec; - return ConvenienceConstructor; + createMarkupForProperty: function(name, value) { + if (DOMProperty.isStandardName[name]) { + if (value == null || DOMProperty.hasBooleanValue[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 { + return null; + } }, /** - * Marks the provided method to be automatically bound to the component. - * This means the method's context will always be the component. + * Sets the value for a property on a node. * - * React.createClass({ - * handleClick: React.autoBind(function() { - * this.setState({jumping: true}); - * }), - * render: function() { - * return Jump; - * } - * }); + * @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 (DOMProperty.mustUseAttribute[name]) { + if (DOMProperty.hasBooleanValue[name] && !value) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + 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)) { + node.setAttribute(name, value); + } + }, + + /** + * Deletes the value for a property on a node. * - * @param {function} method Method to be bound. - * @public + * @param {DOMElement} node + * @param {string} name */ - autoBind: function(method) { - function unbound() { - invariant( - false, - 'React.autoBind(...): Attempted to invoke an auto-bound method that ' + - 'was not correctly defined on the class specification.' - ); + 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]; + node[propName] = DOMProperty.getDefaultValueForProperty( + node.nodeName, + name + ); + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.removeAttribute(name); } - unbound.__reactAutoBind = method; - return unbound; } }; -module.exports = ReactCompositeComponent; +module.exports = DOMPropertyOperations; -})() -},{"./ReactComponent":3,"./ReactCurrentOwner":7,"./ReactOwner":8,"./ReactPropTransferer":9,"./invariant":10,"./keyMirror":11,"./merge":12,"./mixInto":13}],3:[function(require,module,exports){ +},{"./DOMProperty":7,"./escapeTextForBrowser":65,"./memoizeStringOnly":80}],9:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -904,95 +1248,1887 @@ module.exports = ReactCompositeComponent; * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule ReactComponent + * @providesModule Danger */ +/*jslint evil: true, sub: true */ + "use strict"; var ExecutionEnvironment = require("./ExecutionEnvironment"); -var ReactCurrentOwner = require("./ReactCurrentOwner"); -var ReactDOMIDOperations = require("./ReactDOMIDOperations"); -var ReactMount = require("./ReactMount"); -var ReactOwner = require("./ReactOwner"); -var ReactReconcileTransaction = require("./ReactReconcileTransaction"); -var invariant = require("./invariant"); -var keyMirror = require("./keyMirror"); -var merge = require("./merge"); +var throwIf = require("./throwIf"); + +var DOM_UNSUPPORTED; +var NO_MARKUP_PARENT; +var NO_MULTI_MARKUP; +if (true) { + DOM_UNSUPPORTED = + 'You may not insert markup into the document while you are in a worker ' + + 'thread. It\'s not you, it\'s me. This is likely the fault of the ' + + 'framework. Please report this immediately.'; + NO_MARKUP_PARENT = + 'You have attempted to inject markup without a suitable parent. This is ' + + 'likely the fault of the framework - please report immediately.'; + NO_MULTI_MARKUP = + 'The framework has attempted to either insert zero or multiple markup ' + + 'roots into a single location when it should not. This is a serious ' + + 'error - a fault of the framework - please report immediately.'; +} + +var validateMarkupParams; +if (true) { + validateMarkupParams = function(parentNode, markup) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + throwIf(!parentNode || !parentNode.tagName, NO_MARKUP_PARENT); + throwIf(!markup, NO_MULTI_MARKUP); + }; +} /** - * Prop key that references a component's owner. - * @private + * Dummy container used to render all markup. */ -var OWNER = '{owner}'; +var dummyNode = ExecutionEnvironment.canUseDOM ? + document.createElement('div') : + null; /** - * Every React component is in one of these life cycles. + * Some browsers cannot use `innerHTML` to render certain elements standalone, + * so we wrap them, render the wrapped nodes, then extract the desired node. */ -var ComponentLifeCycle = keyMirror({ - /** - * Mounted components have a DOM node representation and are capable of - * receiving new props. - */ - MOUNTED: null, - /** - * Unmounted components are inactive and cannot receive new props. - */ - UNMOUNTED: null -}); +var markupWrap = { + 'option': [1, ''], + 'legend': [1, '
', '
'], + 'area': [1, '', ''], + 'param': [1, '', ''], + 'thead': [1, '', '
'], + 'tr': [2, '', '
'], + 'col': [2, '', '
'], + 'td': [3, '', '
'] +}; +markupWrap['optgroup'] = markupWrap['option']; +markupWrap['tbody'] = markupWrap['thead']; +markupWrap['tfoot'] = markupWrap['thead']; +markupWrap['colgroup'] = markupWrap['thead']; +markupWrap['caption'] = markupWrap['thead']; +markupWrap['th'] = markupWrap['td']; /** - * Components are the basic units of composition in React. - * - * Every component accepts a set of keyed input parameters known as "props" that - * are initialized by the constructor. Once a component is mounted, the props - * can be mutated using `setProps` or `replaceProps`. - * - * Every component is capable of the following operations: - * - * `mountComponent` - * Initializes the component, renders markup, and registers event listeners. - * - * `receiveProps` - * Updates the rendered DOM nodes given a new set of props. - * - * `unmountComponent` - * Releases any resources allocated by this component. + * In IE8, certain elements cannot render alone, so wrap all elements. + */ +var defaultWrap = [1, '?
', '
']; + +/** + * Feature detection, remove wraps that are unnecessary for the current browser. + */ +if (dummyNode) { + for (var nodeName in markupWrap) { + if (!markupWrap.hasOwnProperty(nodeName)) { + continue; + } + dummyNode.innerHTML = '<' + nodeName + '>'; + if (dummyNode.firstChild) { + markupWrap[nodeName] = null; + } + } + dummyNode.innerHTML = ''; + if (dummyNode.firstChild) { + defaultWrap = null; + } +} + +/** + * Renders markup into nodes. The returned HTMLCollection is live and should be + * used immediately (or at least before the next invocation to `renderMarkup`). * - * Components can also be "owned" by other components. Being owned by another - * component means being constructed by that component. This is different from - * being the child of a component, which means having a DOM representation that - * is a child of the DOM representation of that component. + * 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). + * @see http://jsperf.com/extract-nodename * - * @class ReactComponent + * @param {string} markup + * @return {*} An HTMLCollection. */ -var ReactComponent = { +function renderMarkup(markup) { + var node = dummyNode; + var nodeName = markup.substring(1, markup.indexOf(' ')); - /** - * @param {?object} object - * @return {boolean} True if `object` is a valid component. - * @final - */ - isValidComponent: function(object) { - return !!( - object && - typeof object.mountComponentIntoNode === 'function' && - typeof object.receiveProps === 'function' - ); - }, + var wrap = markupWrap[nodeName.toLowerCase()] || defaultWrap; + if (wrap) { + node.innerHTML = wrap[1] + markup + wrap[2]; - /** - * @internal - */ - LifeCycle: ComponentLifeCycle, + var wrapDepth = wrap[0]; + while (wrapDepth--) { + node = node.lastChild; + } + } else { + node.innerHTML = markup; + } + return node.childNodes; +} - /** - * React references `ReactDOMIDOperations` using this property in order to - * allow dependency injection. - * - * @internal - */ - DOMIDOperations: ReactDOMIDOperations, +/** + * Inserts node after 'after'. If 'after' is null, inserts it after nothing, + * which is inserting it at the beginning. + * + * @param {Element} elem Parent element. + * @param {Element} insert Element to insert. + * @param {Element} after Element to insert after. + * @return {Element} Element that was inserted. + */ +function insertNodeAfterNode(elem, insert, after) { + if (true) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + } + if (after) { + if (after.nextSibling) { + return elem.insertBefore(insert, after.nextSibling); + } else { + return elem.appendChild(insert); + } + } else { + return elem.insertBefore(insert, elem.firstChild); + } +} + +/** + * Slow: Should only be used when it is known there are a few (or one) element + * in the node list. + * @param {Element} parentRootDomNode Parent element. + * @param {HTMLCollection} htmlCollection HTMLCollection to insert. + * @param {Element} after Element to insert the node list after. + */ +function inefficientlyInsertHTMLCollectionAfter( + parentRootDomNode, + htmlCollection, + after) { + + if (true) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + } + var ret; + var originalLength = htmlCollection.length; + // Access htmlCollection[0] because htmlCollection shrinks as we remove items. + // `insertNodeAfterNode` will remove items from the htmlCollection. + for (var i = 0; i < originalLength; i++) { + ret = + insertNodeAfterNode(parentRootDomNode, htmlCollection[0], ret || after); + } +} + +/** + * Super-dangerously inserts markup into existing DOM structure. Seriously, you + * don't want to use this module unless you are building a framework. This + * requires that the markup that you are inserting represents the root of a + * tree. We do not support the case where there `markup` represents several + * roots. + * + * @param {Element} parentNode Parent DOM element. + * @param {string} markup Markup to dangerously insert. + * @param {number} index Position to insert markup at. + */ +function dangerouslyInsertMarkupAt(parentNode, markup, index) { + if (true) { + validateMarkupParams(parentNode, markup); + } + var htmlCollection = renderMarkup(markup); + var afterNode = index ? parentNode.childNodes[index - 1] : null; + inefficientlyInsertHTMLCollectionAfter(parentNode, htmlCollection, afterNode); +} + +/** + * Replaces a node with a string of markup at its current position within its + * parent. `childNode` must be in the document (or at least within a parent + * node). The string of markup must represent a tree of markup with a single + * root. + * + * @param {Element} childNode Child node to replace. + * @param {string} markup Markup to dangerously replace child with. + */ +function dangerouslyReplaceNodeWithMarkup(childNode, markup) { + var parentNode = childNode.parentNode; + if (true) { + validateMarkupParams(parentNode, markup); + } + var htmlCollection = renderMarkup(markup); + if (true) { + throwIf(htmlCollection.length !== 1, NO_MULTI_MARKUP); + } + parentNode.replaceChild(htmlCollection[0], childNode); +} + +var Danger = { + dangerouslyInsertMarkupAt: dangerouslyInsertMarkupAt, + dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup +}; + +module.exports = Danger; + +},{"./ExecutionEnvironment":19,"./throwIf":86}],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 DefaultDOMPropertyConfig + */ + +"use strict"; + +var DOMProperty = require("./DOMProperty"); + +var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE; +var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY; +var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE; +var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS; + +var DefaultDOMPropertyConfig = { + isCustomAttribute: RegExp.prototype.test.bind( + /^(data|aria)-[a-z_][a-z\d_.\-]*$/ + ), + Properties: { + /** + * Standard Properties + */ + accessKey: null, + accept: null, + action: null, + ajaxify: MUST_USE_ATTRIBUTE, + allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, + alt: null, + autoComplete: null, + autoFocus: HAS_BOOLEAN_VALUE, + autoPlay: HAS_BOOLEAN_VALUE, + cellPadding: null, + cellSpacing: null, + checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + className: MUST_USE_PROPERTY, + colSpan: null, + contentEditable: null, + contextMenu: MUST_USE_ATTRIBUTE, + controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + data: null, // For `` acts as `src`. + dateTime: MUST_USE_ATTRIBUTE, + dir: null, + disabled: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + draggable: null, + encType: null, + height: MUST_USE_ATTRIBUTE, + hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, + href: null, + htmlFor: null, + icon: null, + id: MUST_USE_PROPERTY, + label: null, + lang: null, + list: null, + max: null, + maxLength: MUST_USE_ATTRIBUTE, + method: null, + min: null, + multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + name: null, + pattern: null, + poster: null, + preload: null, + placeholder: null, + radioGroup: null, + rel: null, + readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + required: HAS_BOOLEAN_VALUE, + role: MUST_USE_ATTRIBUTE, + scrollLeft: MUST_USE_PROPERTY, + scrollTop: MUST_USE_PROPERTY, + selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + size: null, + spellCheck: null, + src: null, + step: null, + style: null, + tabIndex: null, + target: null, + title: null, + type: null, + value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS, + width: MUST_USE_ATTRIBUTE, + wmode: MUST_USE_ATTRIBUTE, + /** + * SVG Properties + */ + cx: MUST_USE_PROPERTY, + cy: MUST_USE_PROPERTY, + d: MUST_USE_PROPERTY, + fill: MUST_USE_PROPERTY, + fx: MUST_USE_PROPERTY, + fy: MUST_USE_PROPERTY, + points: MUST_USE_PROPERTY, + r: MUST_USE_PROPERTY, + stroke: MUST_USE_PROPERTY, + strokeLinecap: MUST_USE_PROPERTY, + strokeWidth: MUST_USE_PROPERTY, + transform: MUST_USE_PROPERTY, + x: MUST_USE_PROPERTY, + x1: MUST_USE_PROPERTY, + x2: MUST_USE_PROPERTY, + version: MUST_USE_PROPERTY, + viewBox: MUST_USE_PROPERTY, + y: MUST_USE_PROPERTY, + y1: MUST_USE_PROPERTY, + y2: MUST_USE_PROPERTY, + spreadMethod: MUST_USE_PROPERTY, + offset: MUST_USE_PROPERTY, + stopColor: MUST_USE_PROPERTY, + stopOpacity: MUST_USE_PROPERTY, + gradientUnits: MUST_USE_PROPERTY, + gradientTransform: MUST_USE_PROPERTY + }, + DOMAttributeNames: { + className: 'class', + htmlFor: 'for', + strokeLinecap: 'stroke-linecap', + strokeWidth: 'stroke-width', + stopColor: 'stop-color', + stopOpacity: 'stop-opacity' + }, + DOMPropertyNames: { + autoComplete: 'autocomplete', + autoFocus: 'autofocus', + autoPlay: 'autoplay', + encType: 'enctype', + radioGroup: 'radiogroup', + spellCheck: 'spellcheck' + }, + DOMMutationMethods: { + /** + * Setting `className` to null may cause it to be set to the string "null". + * + * @param {DOMElement} node + * @param {*} value + */ + className: function(node, value) { + node.className = value || ''; + } + } +}; + +module.exports = DefaultDOMPropertyConfig; + +},{"./DOMProperty":7}],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 DefaultEventPluginOrder + */ + +"use strict"; + + var keyOf = require("./keyOf"); + +/** + * Module that is injectable into `EventPluginHub`, that specifies a + * deterministic ordering of `EventPlugin`s. A convenient way to reason about + * plugins, without having to package every one of them. This is better than + * having plugins be ordered in the same order that they are injected because + * that ordering would be influenced by the packaging order. + * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that + * preventing default on events is convenient in `SimpleEventPlugin` handlers. + */ +var DefaultEventPluginOrder = [ + keyOf({ResponderEventPlugin: null}), + keyOf({SimpleEventPlugin: null}), + keyOf({TapEventPlugin: null}), + keyOf({EnterLeaveEventPlugin: null}), + keyOf({ChangeEventPlugin: null}), + keyOf({AnalyticsEventPlugin: null}) +]; + +module.exports = DefaultEventPluginOrder; + +},{"./keyOf":79}],12:[function(require,module,exports){ +(function(){/** + * 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 EnterLeaveEventPlugin + * @typechecks static-only + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var ReactInstanceHandles = require("./ReactInstanceHandles"); +var SyntheticMouseEvent = require("./SyntheticMouseEvent"); + +var ReactID = require("./ReactID"); +var keyOf = require("./keyOf"); + +var topLevelTypes = EventConstants.topLevelTypes; +var getFirstReactDOM = ReactInstanceHandles.getFirstReactDOM; + +var eventTypes = { + mouseEnter: {registrationName: keyOf({onMouseEnter: null})}, + mouseLeave: {registrationName: keyOf({onMouseLeave: null})} +}; + +var EnterLeaveEventPlugin = { + + eventTypes: eventTypes, + + /** + * For almost every interaction we care about, there will be both a top-level + * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that + * we do not extract duplicate events. However, moving the mouse into the + * browser from outside will not fire a `mouseout` event. In this case, we use + * the `mouseover` top-level event. + * + * @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) { + if (topLevelType === topLevelTypes.topMouseOver && + (nativeEvent.relatedTarget || nativeEvent.fromElement)) { + return null; + } + if (topLevelType !== topLevelTypes.topMouseOut && + topLevelType !== topLevelTypes.topMouseOver) { + // Must not be a mouse in or mouse out - ignoring. + return null; + } + + var from, to; + if (topLevelType === topLevelTypes.topMouseOut) { + from = topLevelTarget; + to = + getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) || + ExecutionEnvironment.global; + } else { + from = ExecutionEnvironment.global; + to = topLevelTarget; + } + + if (from === to) { + // Nothing pertains to our managed components. + return null; + } + + var fromID = from ? ReactID.getID(from) : ''; + var toID = to ? ReactID.getID(to) : ''; + + var leave = SyntheticMouseEvent.getPooled( + eventTypes.mouseLeave, + fromID, + nativeEvent + ); + var enter = SyntheticMouseEvent.getPooled( + eventTypes.mouseEnter, + toID, + nativeEvent + ); + + EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID); + return [leave, enter]; + } + +}; + +module.exports = EnterLeaveEventPlugin; + +})() +},{"./EventConstants":13,"./EventPropagators":18,"./ExecutionEnvironment":19,"./ReactID":35,"./ReactInstanceHandles":37,"./SyntheticMouseEvent":53,"./keyOf":79}],13:[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 EventConstants + */ + +"use strict"; + +var keyMirror = require("./keyMirror"); + +var PropagationPhases = keyMirror({bubbled: null, captured: null}); + +/** + * Types of raw signals from the browser caught at the top level. + */ +var topLevelTypes = keyMirror({ + topBlur: null, + topChange: null, + topClick: null, + topDOMCharacterDataModified: null, + topDoubleClick: null, + topDrag: null, + topDragEnd: null, + topDragEnter: null, + topDragExit: null, + topDragLeave: null, + topDragOver: null, + topDragStart: null, + topDrop: null, + topFocus: null, + topInput: null, + topKeyDown: null, + topKeyPress: null, + topKeyUp: null, + topMouseDown: null, + topMouseMove: null, + topMouseOut: null, + topMouseOver: null, + topMouseUp: null, + topScroll: null, + topSelectionChange: null, + topSubmit: null, + topTouchCancel: null, + topTouchEnd: null, + topTouchMove: null, + topTouchStart: null, + topWheel: null +}); + +var EventConstants = { + topLevelTypes: topLevelTypes, + PropagationPhases: PropagationPhases +}; + +module.exports = EventConstants; + +},{"./keyMirror":78}],14:[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 EventListener + */ + +/** + * Upstream version of event listener. Does not take into account specific + * nature of platform. + */ +var EventListener = { + /** + * Listens to bubbled events on a DOM node. + * + * @param {Element} el DOM element to register listener on. + * @param {string} handlerBaseName 'click'/'mouseover' + * @param {Function!} cb Callback function + */ + listen: function(el, handlerBaseName, cb) { + if (el.addEventListener) { + el.addEventListener(handlerBaseName, cb, false); + } else if (el.attachEvent) { + el.attachEvent('on' + handlerBaseName, cb); + } + }, + + /** + * Listens to captured events on a DOM node. + * + * @see `EventListener.listen` for params. + * @throws Exception if addEventListener is not supported. + */ + capture: function(el, handlerBaseName, cb) { + if (!el.addEventListener) { + if (true) { + console.error( + 'You are attempting to use addEventlistener ' + + 'in a browser that does not support it support it.' + + 'This likely means that you will not receive events that ' + + 'your application relies on (such as scroll).'); + } + return; + } else { + el.addEventListener(handlerBaseName, cb, true); + } + } +}; + +module.exports = EventListener; + +},{}],15:[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 EventPluginHub + */ + +"use strict"; + +var CallbackRegistry = require("./CallbackRegistry"); +var EventPluginRegistry = require("./EventPluginRegistry"); +var EventPluginUtils = require("./EventPluginUtils"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); +var invariant = require("./invariant"); + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; + +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function(event) { + if (event) { + var executeDispatch = EventPluginUtils.executeDispatch; + // Plugins can provide custom behavior when dispatching events. + var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event); + if (PluginModule && PluginModule.executeDispatch) { + executeDispatch = PluginModule.executeDispatch; + } + EventPluginUtils.executeDispatchesInOrder(event, executeDispatch); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ +var EventPluginHub = { + + /** + * Methods for injecting dependencies. + */ + injection: { + + /** + * @param {object} InjectedInstanceHandle + * @public + */ + injectInstanceHandle: EventPropagators.injection.injectInstanceHandle, + + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName + + }, + + registrationNames: EventPluginRegistry.registrationNames, + + putListener: CallbackRegistry.putListener, + + getListener: CallbackRegistry.getListener, + + deleteListener: CallbackRegistry.deleteListener, + + deleteAllListeners: CallbackRegistry.deleteAllListeners, + + /** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @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. + * @internal + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + var events; + var plugins = EventPluginRegistry.plugins; + for (var i = 0, l = plugins.length; i < l; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent + ); + if (extractedEvents) { + events = accumulate(events, extractedEvents); + } + } + } + return events; + }, + + /** + * Enqueues a synthetic event that should be dispatched when + * `processEventQueue` is invoked. + * + * @param {*} events An accumulation of synthetic events. + * @internal + */ + enqueueEvents: function(events) { + if (events) { + eventQueue = accumulate(eventQueue, events); + } + }, + + /** + * Dispatches all synthetic events on the event queue. + * + * @internal + */ + processEventQueue: function() { + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + forEachAccumulated(processingEventQueue, executeDispatchesAndRelease); + invariant( + !eventQueue, + 'processEventQueue(): Additional events were enqueued while processing ' + + 'an event queue. Support for this has not yet been implemented.' + ); + } + +}; + +if (ExecutionEnvironment.canUseDOM) { + window.EventPluginHub = EventPluginHub; +} + +module.exports = EventPluginHub; + +},{"./CallbackRegistry":4,"./EventPluginRegistry":16,"./EventPluginUtils":17,"./EventPropagators":18,"./ExecutionEnvironment":19,"./accumulate":60,"./forEachAccumulated":68,"./invariant":75}],16:[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 EventPluginRegistry + * @typechecks static-only + */ + +"use strict"; + +var invariant = require("./invariant"); + +/** + * Injectable ordering of event plugins. + */ +var EventPluginOrder = null; + +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; + +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!EventPluginOrder) { + // Wait until an `EventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var PluginModule = namesToPlugins[pluginName]; + var pluginIndex = EventPluginOrder.indexOf(pluginName); + invariant( + pluginIndex > -1, + 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + + 'the plugin ordering, `%s`.', + pluginName + ); + if (EventPluginRegistry.plugins[pluginIndex]) { + continue; + } + invariant( + PluginModule.extractEvents, + 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + + 'method, but `%s` does not.', + pluginName + ); + EventPluginRegistry.plugins[pluginIndex] = PluginModule; + var publishedEvents = PluginModule.eventTypes; + for (var eventName in publishedEvents) { + invariant( + publishEventForPlugin(publishedEvents[eventName], PluginModule), + 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', + eventName, + pluginName + ); + } + } +} + +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, PluginModule) { + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName(phasedRegistrationName, PluginModule); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName(dispatchConfig.registrationName, PluginModule); + return true; + } + return false; +} + +/** + * Publishes a registration name that is used to identify dispatched events and + * can be used with `EventPluginHub.putListener` to register listeners. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, PluginModule) { + invariant( + !EventPluginRegistry.registrationNames[registrationName], + 'EventPluginHub: More than one plugin attempted to publish the same ' + + 'registration name, `%s`.', + registrationName + ); + EventPluginRegistry.registrationNames[registrationName] = PluginModule; + EventPluginRegistry.registrationNamesKeys.push(registrationName); +} + +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ +var EventPluginRegistry = { + + /** + * Ordered list of injected plugins. + */ + plugins: [], + + /** + * Mapping from registration names to plugin modules. + */ + registrationNames: {}, + + /** + * The keys of `registrationNames`. + */ + registrationNamesKeys: [], + + /** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ + injectEventPluginOrder: function(InjectedEventPluginOrder) { + invariant( + !EventPluginOrder, + 'EventPluginRegistry: Cannot inject event plugin ordering more than once.' + ); + // Clone the ordering so it cannot be dynamically mutated. + EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder); + recomputePluginOrdering(); + }, + + /** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var PluginModule = injectedNamesToPlugins[pluginName]; + if (namesToPlugins[pluginName] !== PluginModule) { + invariant( + !namesToPlugins[pluginName], + 'EventPluginRegistry: Cannot inject two different event plugins ' + + 'using the same name, `%s`.', + pluginName + ); + namesToPlugins[pluginName] = PluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } + }, + + /** + * Looks up the plugin for the supplied event. + * + * @param {object} event A synthetic event. + * @return {?object} The plugin that created the supplied event. + * @internal + */ + getPluginModuleForEvent: function(event) { + var dispatchConfig = event.dispatchConfig; + if (dispatchConfig.registrationName) { + return EventPluginRegistry.registrationNames[ + dispatchConfig.registrationName + ] || null; + } + for (var phase in dispatchConfig.phasedRegistrationNames) { + if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) { + continue; + } + var PluginModule = EventPluginRegistry.registrationNames[ + dispatchConfig.phasedRegistrationNames[phase] + ]; + if (PluginModule) { + return PluginModule; + } + } + return null; + }, + + /** + * Exposed for unit testing. + * @private + */ + _resetEventPlugins: function() { + EventPluginOrder = null; + for (var pluginName in namesToPlugins) { + if (namesToPlugins.hasOwnProperty(pluginName)) { + delete namesToPlugins[pluginName]; + } + } + EventPluginRegistry.plugins.length = 0; + var registrationNames = EventPluginRegistry.registrationNames; + for (var registrationName in registrationNames) { + if (registrationNames.hasOwnProperty(registrationName)) { + delete registrationNames[registrationName]; + } + } + EventPluginRegistry.registrationNamesKeys.length = 0; + } + +}; + +module.exports = EventPluginRegistry; + +},{"./invariant":75}],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. + * + * @providesModule EventPluginUtils + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); + +var invariant = require("./invariant"); + +var topLevelTypes = EventConstants.topLevelTypes; + +function isEndish(topLevelType) { + return topLevelType === topLevelTypes.topMouseUp || + topLevelType === topLevelTypes.topTouchEnd || + topLevelType === topLevelTypes.topTouchCancel; +} + +function isMoveish(topLevelType) { + return topLevelType === topLevelTypes.topMouseMove || + topLevelType === topLevelTypes.topTouchMove; +} +function isStartish(topLevelType) { + return topLevelType === topLevelTypes.topMouseDown || + topLevelType === topLevelTypes.topTouchStart; +} + +var validateEventDispatches; +if (true) { + validateEventDispatches = function(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + + var listenersIsArr = Array.isArray(dispatchListeners); + var idsIsArr = Array.isArray(dispatchIDs); + var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0; + var listenersLen = listenersIsArr ? + dispatchListeners.length : + dispatchListeners ? 1 : 0; + + invariant( + idsIsArr === listenersIsArr && IDsLen === listenersLen, + 'EventPluginUtils: Invalid `event`.' + ); + }; +} + +/** + * Invokes `cb(event, listener, id)`. Avoids using call if no scope is + * provided. The `(listener,id)` pair effectively forms the "dispatch" but are + * kept separate to conserve memory. + */ +function forEachEventDispatch(event, cb) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + if (true) { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and IDs are two parallel arrays that are always in sync. + cb(event, dispatchListeners[i], dispatchIDs[i]); + } + } else if (dispatchListeners) { + cb(event, dispatchListeners, dispatchIDs); + } +} + +/** + * Default implementation of PluginModule.executeDispatch(). + * @param {SyntheticEvent} SyntheticEvent to handle + * @param {function} Application-level callback + * @param {string} domID DOM id to pass to the callback. + */ +function executeDispatch(event, listener, domID) { + listener(event, domID); +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event, executeDispatch) { + forEachEventDispatch(event, executeDispatch); + event._dispatchListeners = null; + event._dispatchIDs = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return id of the first dispatch execution who's listener returns true, or + * null if no listener returned true. + */ +function executeDispatchesInOrderStopAtTrue(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + if (true) { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and IDs are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchIDs[i])) { + return dispatchIDs[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchIDs)) { + return dispatchIDs; + } + } + return null; +} + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return The return value of executing the single dispatch. + */ +function executeDirectDispatch(event) { + if (true) { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchID = event._dispatchIDs; + invariant( + !Array.isArray(dispatchListener), + 'executeDirectDispatch(...): Invalid `event`.' + ); + var res = dispatchListener ? + dispatchListener(event, dispatchID) : + null; + event._dispatchListeners = null; + event._dispatchIDs = null; + return res; +} + +/** + * @param {SyntheticEvent} event + * @return {bool} True iff number of dispatches accumulated is greater than 0. + */ +function hasDispatches(event) { + return !!event._dispatchListeners; +} + +/** + * General utilities that are useful in creating custom Event Plugins. + */ +var EventPluginUtils = { + isEndish: isEndish, + isMoveish: isMoveish, + isStartish: isStartish, + executeDispatchesInOrder: executeDispatchesInOrder, + executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, + executeDirectDispatch: executeDirectDispatch, + hasDispatches: hasDispatches, + executeDispatch: executeDispatch +}; + +module.exports = EventPluginUtils; + +},{"./EventConstants":13,"./invariant":75}],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. + * + * @providesModule EventPropagators + */ + +"use strict"; + +var CallbackRegistry = require("./CallbackRegistry"); +var EventConstants = require("./EventConstants"); + +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); +var getListener = CallbackRegistry.getListener; +var PropagationPhases = EventConstants.PropagationPhases; + +/** + * Injected dependencies: + */ + +/** + * - `InstanceHandle`: [required] Module that performs logical traversals of DOM + * hierarchy given ids of the logical DOM elements involved. + */ +var injection = { + InstanceHandle: null, + injectInstanceHandle: function(InjectedInstanceHandle) { + injection.InstanceHandle = InjectedInstanceHandle; + if (true) { + injection.validate(); + } + }, + validate: function() { + var invalid = !injection.InstanceHandle|| + !injection.InstanceHandle.traverseTwoPhase || + !injection.InstanceHandle.traverseEnterLeave; + if (invalid) { + throw new Error('InstanceHandle not injected before use!'); + } + } +}; + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(id, event, propagationPhase) { + var registrationName = + event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(id, registrationName); +} + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(domID, upwards, event) { + if (true) { + if (!domID) { + throw new Error('Dispatching id must not be null'); + } + injection.validate(); + } + var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; + var listener = listenerAtPhase(domID, event, phase); + if (listener) { + event._dispatchListeners = accumulate(event._dispatchListeners, listener); + event._dispatchIDs = accumulate(event._dispatchIDs, domID); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We can not perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + injection.InstanceHandle.traverseTwoPhase( + event.dispatchMarker, + accumulateDirectionalDispatches, + event + ); + } +} + + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(id, ignoredDirection, event) { + if (event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(id, registrationName); + if (listener) { + event._dispatchListeners = accumulate(event._dispatchListeners, listener); + event._dispatchIDs = accumulate(event._dispatchIDs, id); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event.dispatchMarker, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + if (true) { + injection.validate(); + } + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { + if (true) { + injection.validate(); + } + injection.InstanceHandle.traverseEnterLeave( + fromID, + toID, + accumulateDispatches, + leave, + enter + ); +} + + +function accumulateDirectDispatches(events) { + if (true) { + injection.validate(); + } + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} + + + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing event a + * single one. + * + * @constructor EventPropagators + */ +var EventPropagators = { + accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, + accumulateDirectDispatches: accumulateDirectDispatches, + accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, + injection: injection +}; + +module.exports = EventPropagators; + +},{"./CallbackRegistry":4,"./EventConstants":13,"./accumulate":60,"./forEachAccumulated":68}],19:[function(require,module,exports){ +(function(){/** + * 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 ExecutionEnvironment + */ + +/*jslint evil: true */ + +"use strict"; + +var canUseDOM = typeof window !== 'undefined'; + +/** + * Simple, lightweight module assisting with the detection and context of + * Worker. Helps avoid circular dependencies and allows code to reason about + * whether or not they are in a Worker, even if they never include the main + * `ReactWorker` dependency. + */ +var ExecutionEnvironment = { + + canUseDOM: canUseDOM, + + canUseWorkers: typeof Worker !== 'undefined', + + isInWorker: !canUseDOM, // For now, this is true - might change in the future. + + global: new Function('return this;')() + +}; + +module.exports = ExecutionEnvironment; + +})() +},{}],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. + * + * @providesModule PooledClass + */ + +"use strict"; + +/** + * Static poolers. Several custom versions for each potential number of + * arguments. A completely generic pooler is easy to implement, but would + * require accessing the `arguments` object. In each of these, `this` refers to + * the Class itself, not an instance. If any others are needed, simply add them + * here, or in their own files. + */ +var oneArgumentPooler = function(copyFieldsFrom) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, copyFieldsFrom); + return instance; + } else { + return new Klass(copyFieldsFrom); + } +}; + +var twoArgumentPooler = function(a1, a2) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2); + return instance; + } else { + return new Klass(a1, a2); + } +}; + +var threeArgumentPooler = function(a1, a2, a3) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3); + return instance; + } else { + return new Klass(a1, a2, a3); + } +}; + +var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3, a4, a5); + return instance; + } else { + return new Klass(a1, a2, a3, a4, a5); + } +}; + +var standardReleaser = function(instance) { + var Klass = this; + if (instance.destructor) { + instance.destructor(); + } + if (Klass.instancePool.length < Klass.poolSize) { + Klass.instancePool.push(instance); + } +}; + +var DEFAULT_POOL_SIZE = 10; +var DEFAULT_POOLER = oneArgumentPooler; + +/** + * Augments `CopyConstructor` to be a poolable class, augmenting only the class + * itself (statically) not adding any prototypical fields. Any CopyConstructor + * you give this may have a `poolSize` property, and will look for a + * prototypical `destructor` on instances (optional). + * + * @param {Function} CopyConstructor Constructor that can be used to reset. + * @param {Function} pooler Customizable pooler. + */ +var addPoolingTo = function(CopyConstructor, pooler) { + var NewKlass = CopyConstructor; + NewKlass.instancePool = []; + NewKlass.getPooled = pooler || DEFAULT_POOLER; + if (!NewKlass.poolSize) { + NewKlass.poolSize = DEFAULT_POOL_SIZE; + } + NewKlass.release = standardReleaser; + return NewKlass; +}; + +var PooledClass = { + addPoolingTo: addPoolingTo, + oneArgumentPooler: oneArgumentPooler, + twoArgumentPooler: twoArgumentPooler, + threeArgumentPooler: threeArgumentPooler, + fiveArgumentPooler: fiveArgumentPooler +}; + +module.exports = PooledClass; + +},{}],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. + * + * @providesModule React + */ + +"use strict"; + +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactComponent = require("./ReactComponent"); +var ReactDOM = require("./ReactDOM"); +var ReactMount = require("./ReactMount"); +var ReactPropTypes = require("./ReactPropTypes"); +var ReactServerRendering = require("./ReactServerRendering"); + +var ReactDefaultInjection = require("./ReactDefaultInjection"); + +ReactDefaultInjection.inject(); + +var React = { + DOM: ReactDOM, + PropTypes: ReactPropTypes, + initializeTouchEvents: function(shouldUseTouch) { + ReactMount.useTouchEvents = shouldUseTouch; + }, + autoBind: ReactCompositeComponent.autoBind, + createClass: ReactCompositeComponent.createClass, + constructAndRenderComponent: ReactMount.constructAndRenderComponent, + constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID, + renderComponent: ReactMount.renderComponent, + renderComponentToString: ReactServerRendering.renderComponentToString, + unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode, + isValidComponent: ReactComponent.isValidComponent +}; + +module.exports = React; + +},{"./ReactComponent":22,"./ReactCompositeComponent":23,"./ReactDOM":25,"./ReactDefaultInjection":32,"./ReactMount":38,"./ReactPropTypes":44,"./ReactServerRendering":46}],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. + * + * @providesModule ReactComponent + */ + +/*jslint evil: true */ + +"use strict"; + +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactDOMIDOperations = require("./ReactDOMIDOperations"); +var ReactID = require("./ReactID"); +var ReactMount = require("./ReactMount"); +var ReactOwner = require("./ReactOwner"); +var ReactReconcileTransaction = require("./ReactReconcileTransaction"); +var ReactUpdates = require("./ReactUpdates"); + +var invariant = require("./invariant"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); + +/** + * Prop key that references a component's owner. + * @private + */ +var OWNER = '{owner}'; + +/** + * Props key that determines if a component's key was already validated. + * @private + */ +var IS_KEY_VALIDATED = '{is.key.validated}'; + +/** + * Every React component is in one of these life cycles. + */ +var ComponentLifeCycle = keyMirror({ + /** + * Mounted components have a DOM node representation and are capable of + * receiving new props. + */ + MOUNTED: null, + /** + * Unmounted components are inactive and cannot receive new props. + */ + UNMOUNTED: null +}); + +/** + * Warn if there's no key explicitly set on dynamic arrays of children. + * This allows us to keep track of children between updates. + */ + +var ownerHasWarned = {}; + +/** + * Warn if the component doesn't have an explicit key assigned to it. + * This component is in an array. The array could grow and shrink or be + * reordered. All children, that hasn't already been validated, are required to + * have a "key" property assigned to it. + * + * @internal + * @param {ReactComponent} component Component that requires a key. + */ +function validateExplicitKey(component) { + if (component[IS_KEY_VALIDATED] || component.props.key != null) { + return; + } + component[IS_KEY_VALIDATED] = true; + + // We can't provide friendly warnings for top level components. + if (!ReactCurrentOwner.current) { + return; + } + + // Name of the component whose render method tried to pass children. + var currentName = ReactCurrentOwner.current.constructor.displayName; + if (ownerHasWarned.hasOwnProperty(currentName)) { + return; + } + ownerHasWarned[currentName] = true; + + var message = 'Each child in an array should have a unique "key" prop. ' + + 'Check the render method of ' + currentName + '.'; + if (!component.isOwnedBy(ReactCurrentOwner.current)) { + // Name of the component that originally created this child. + var childOwnerName = + component.props[OWNER] && component.props[OWNER].constructor.displayName; + + // Usually the current owner is the offender, but if it accepts + // children as a property, it may be the creator of the child that's + // responsible for assigning it a key. + message += ' It was passed a child from ' + childOwnerName + '.'; + } + + console.warn(message); +} + +/** + * Ensure that every component either is passed in a static location or, if + * if it's passed in an array, has an explicit key property defined. + * + * @internal + * @param {*} component Statically passed child of any type. + * @return {boolean} + */ +function validateChildKeys(component) { + if (Array.isArray(component)) { + for (var i = 0; i < component.length; i++) { + var child = component[i]; + if (ReactComponent.isValidComponent(child)) { + validateExplicitKey(child); + } + } + } else if (ReactComponent.isValidComponent(component)) { + // This component was passed in a valid location. + component[IS_KEY_VALIDATED] = true; + } +} + +/** + * Components are the basic units of composition in React. + * + * Every component accepts a set of keyed input parameters known as "props" that + * are initialized by the constructor. Once a component is mounted, the props + * can be mutated using `setProps` or `replaceProps`. + * + * Every component is capable of the following operations: + * + * `mountComponent` + * Initializes the component, renders markup, and registers event listeners. + * + * `receiveProps` + * Updates the rendered DOM nodes given a new set of props. + * + * `unmountComponent` + * Releases any resources allocated by this component. + * + * Components can also be "owned" by other components. Being owned by another + * component means being constructed by that component. This is different from + * being the child of a component, which means having a DOM representation that + * is a child of the DOM representation of that component. + * + * @class ReactComponent + */ +var ReactComponent = { + + /** + * @param {?object} object + * @return {boolean} True if `object` is a valid component. + * @final + */ + isValidComponent: function(object) { + return !!( + object && + typeof object.mountComponentIntoNode === 'function' && + typeof object.receiveProps === 'function' + ); + }, + + /** + * Generate a key string that identifies a component within a set. + * + * @param {*} component A component that could contain a manual key. + * @param {number} index Index that is used if a manual key is not provided. + * @return {string} + * @internal + */ + getKey: function(component, index) { + if (component && component.props && component.props.key != null) { + // Explicit key + return '' + component.props.key; + } + // Implicit key determined by the index in the set + return '' + index; + }, + + /** + * @internal + */ + LifeCycle: ComponentLifeCycle, + + /** + * React references `ReactDOMIDOperations` using this property in order to + * allow dependency injection. + * + * @internal + */ + DOMIDOperations: ReactDOMIDOperations, /** * React references `ReactReconcileTransaction` using this property in order @@ -1025,53 +3161,57 @@ var ReactComponent = { */ Mixin: { + /** + * Checks whether or not this component is mounted. + * + * @return {boolean} True if mounted, false otherwise. + * @final + * @protected + */ + isMounted: function() { + return this._lifeCycleState === ComponentLifeCycle.MOUNTED; + }, + /** * Returns the DOM node rendered by this component. * - * @return {?DOMElement} The root node of this component. + * @return {DOMElement} The root node of this component. * @final * @protected */ getDOMNode: function() { invariant( - ExecutionEnvironment.canUseDOM, - 'getDOMNode(): The DOM is not supported in the current environment.' - ); - invariant( - this._lifeCycleState === ComponentLifeCycle.MOUNTED, + this.isMounted(), 'getDOMNode(): A component must be mounted to have a DOM node.' ); - var rootNode = this._rootNode; - if (!rootNode) { - rootNode = document.getElementById(this._rootNodeID); - if (!rootNode) { - // TODO: Log the frequency that we reach this path. - rootNode = ReactMount.findReactRenderedDOMNodeSlow(this._rootNodeID); - } - this._rootNode = rootNode; - } - return rootNode; + return ReactID.getNode(this._rootNodeID); }, /** * Sets a subset of the props. * * @param {object} partialProps Subset of the next props. + * @param {?function} callback Called after props are updated. * @final * @public */ - setProps: function(partialProps) { - this.replaceProps(merge(this.props, partialProps)); + setProps: function(partialProps, callback) { + // Merge with `_pendingProps` if it exists, otherwise with existing props. + this.replaceProps( + merge(this._pendingProps || this.props, partialProps), + callback + ); }, /** * Replaces all of the props. * * @param {object} props New props. + * @param {?function} callback Called after props are updated. * @final * @public */ - replaceProps: function(props) { + replaceProps: function(props, callback) { invariant( !this.props[OWNER], 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + @@ -1080,9 +3220,8 @@ var ReactComponent = { '`render` method to pass the correct value as props to the component ' + 'where it is created.' ); - var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); - transaction.perform(this.receiveProps, this, props, transaction); - ReactComponent.ReactReconcileTransaction.release(transaction); + this._pendingProps = props; + ReactUpdates.enqueueUpdate(this, callback); }, /** @@ -1097,13 +3236,31 @@ var ReactComponent = { */ construct: function(initialProps, children) { this.props = initialProps || {}; - if (typeof children !== 'undefined') { - this.props.children = children; - } // Record the component responsible for creating this component. this.props[OWNER] = ReactCurrentOwner.current; // All components start unmounted. this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; + + this._pendingProps = null; + this._pendingCallbacks = null; + + // Children can be more than one argument + var childrenLength = arguments.length - 1; + if (childrenLength === 1) { + if (true) { + validateChildKeys(children); + } + this.props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + if (true) { + validateChildKeys(arguments[i + 1]); + } + childArray[i] = arguments[i + 1]; + } + this.props.children = childArray; + } }, /** @@ -1121,7 +3278,7 @@ var ReactComponent = { */ mountComponent: function(rootID, transaction) { invariant( - this._lifeCycleState === ComponentLifeCycle.UNMOUNTED, + !this.isMounted(), 'mountComponent(%s, ...): Can only mount an unmounted component.', rootID ); @@ -1146,14 +3303,14 @@ var ReactComponent = { */ unmountComponent: function() { invariant( - this._lifeCycleState === ComponentLifeCycle.MOUNTED, + this.isMounted(), 'unmountComponent(): Can only unmount a mounted component.' ); var props = this.props; if (props.ref != null) { ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]); } - this._rootNode = null; + ReactID.purgeID(this._rootNodeID); this._rootNodeID = null; this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; }, @@ -1168,22 +3325,64 @@ var ReactComponent = { * @param {ReactReconcileTransaction} transaction * @internal */ - receiveProps: function(nextProps, transaction) { - invariant( - this._lifeCycleState === ComponentLifeCycle.MOUNTED, - 'receiveProps(...): Can only update a mounted component.' - ); + receiveProps: function(nextProps, transaction) { + invariant( + this.isMounted(), + 'receiveProps(...): Can only update a mounted component.' + ); + this._pendingProps = nextProps; + this._performUpdateIfNecessary(transaction); + }, + + /** + * Call `_performUpdateIfNecessary` within a new transaction. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + performUpdateIfNecessary: function() { + var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); + transaction.perform(this._performUpdateIfNecessary, this, transaction); + ReactComponent.ReactReconcileTransaction.release(transaction); + }, + + /** + * If `_pendingProps` is set, update the component. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + _performUpdateIfNecessary: function(transaction) { + if (this._pendingProps == null) { + return; + } + var prevProps = this.props; + this.props = this._pendingProps; + this._pendingProps = null; + this.updateComponent(transaction, prevProps); + }, + + /** + * Updates the component's currently mounted representation. + * + * @param {ReactReconcileTransaction} transaction + * @param {object} prevProps + * @internal + */ + updateComponent: function(transaction, prevProps) { var props = this.props; // If either the owner or a `ref` has changed, make sure the newest owner // has stored a reference to `this`, and the previous owner (if different) // has forgotten the reference to `this`. - if (nextProps[OWNER] !== props[OWNER] || nextProps.ref !== props.ref) { - if (props.ref != null) { - ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]); + if (props[OWNER] !== prevProps[OWNER] || props.ref !== prevProps.ref) { + if (prevProps.ref != null) { + ReactOwner.removeComponentAsRefFrom( + this, prevProps.ref, prevProps[OWNER] + ); } // Correct, even if the owner is the same, and only the ref has changed. - if (nextProps.ref != null) { - ReactOwner.addComponentAsRefTo(this, nextProps.ref, nextProps[OWNER]); + if (props.ref != null) { + ReactOwner.addComponentAsRefTo(this, props.ref, props[OWNER]); } } }, @@ -1193,18 +3392,20 @@ var ReactComponent = { * * @param {string} rootID DOM ID of the root node. * @param {DOMElement} container DOM element to mount into. + * @param {boolean} shouldReuseMarkup If true, do not insert markup * @final * @internal * @see {ReactMount.renderComponent} */ - mountComponentIntoNode: function(rootID, container) { + mountComponentIntoNode: function(rootID, container, shouldReuseMarkup) { var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); transaction.perform( this._mountComponentIntoNode, this, rootID, container, - transaction + transaction, + shouldReuseMarkup ); ReactComponent.ReactReconcileTransaction.release(transaction); }, @@ -1213,14 +3414,27 @@ var ReactComponent = { * @param {string} rootID DOM ID of the root node. * @param {DOMElement} container DOM element to mount into. * @param {ReactReconcileTransaction} transaction + * @param {boolean} shouldReuseMarkup If true, do not insert markup * @final * @private */ - _mountComponentIntoNode: function(rootID, container, transaction) { + _mountComponentIntoNode: function( + rootID, + container, + transaction, + shouldReuseMarkup) { + invariant( + container && container.nodeType === 1, + 'mountComponentIntoNode(...): Target container is not a DOM element.' + ); var renderStart = Date.now(); var markup = this.mountComponent(rootID, transaction); ReactMount.totalInstantiationTime += (Date.now() - renderStart); + if (shouldReuseMarkup) { + return; + } + var injectionStart = Date.now(); // Asynchronously inject markup by ensuring that the container is not in // the document when settings its `innerHTML`. @@ -1266,183 +3480,31 @@ var ReactComponent = { */ isOwnedBy: function(owner) { return this.props[OWNER] === owner; - } - - } + }, -}; + /** + * Gets another component, that shares the same owner as this one, by ref. + * + * @param {string} ref of a sibling Component. + * @return {?ReactComponent} the actual sibling Component. + * @final + * @internal + */ + getSiblingByRef: function(ref) { + var owner = this.props[OWNER]; + if (!owner || !owner.refs) { + return null; + } + return owner.refs[ref]; + } -function logDeprecated(msg) { - if (true) { - throw new Error(msg); } -} -/** - * @deprecated - */ -ReactComponent.Mixin.update = function(props) { - logDeprecated('this.update() is deprecated. Use this.setProps()'); - this.setProps(props); -}; -ReactComponent.Mixin.updateAll = function(props) { - logDeprecated('this.updateAll() is deprecated. Use this.replaceProps()'); - this.replaceProps(props); }; module.exports = ReactComponent; -},{"./ExecutionEnvironment":14,"./ReactCurrentOwner":7,"./ReactDOMIDOperations":15,"./ReactMount":5,"./ReactOwner":8,"./ReactReconcileTransaction":16,"./invariant":10,"./keyMirror":11,"./merge":12}],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 ReactDOM - * @typechecks - */ - -"use strict"; - -var ReactNativeComponent = require("./ReactNativeComponent"); - -var mergeInto = require("./mergeInto"); -var objMapKeyVal = require("./objMapKeyVal"); - -/** - * Creates a new React class that is idempotent and capable of containing other - * React components. It accepts event listeners and DOM properties that are - * valid according to `DOMProperty`. - * - * - Event listeners: `onClick`, `onMouseDown`, etc. - * - DOM properties: `className`, `name`, `title`, etc. - * - * The `style` property functions differently from the DOM API. It accepts an - * object mapping of style properties to values. - * - * @param {string} tag Tag name (e.g. `div`). - * @param {boolean} omitClose True if the close tag should be omitted. - * @private - */ -function createDOMComponentClass(tag, omitClose) { - var Constructor = function(initialProps, children) { - this.construct(initialProps, children); - }; - - Constructor.prototype = new ReactNativeComponent(tag, omitClose); - Constructor.prototype.constructor = Constructor; - - return function(props, children) { - return new Constructor(props, children); - }; -} - -/** - * Creates a mapping from supported HTML tags to `ReactNativeComponent` classes. - * This is also accessible via `React.DOM`. - * - * @public - */ -var ReactDOM = objMapKeyVal({ - a: false, - abbr: false, - address: false, - audio: false, - b: false, - body: false, - br: true, - button: false, - code: false, - col: true, - colgroup: false, - dd: false, - div: false, - section: false, - dl: false, - dt: false, - em: false, - embed: true, - fieldset: false, - footer: false, - // Danger: this gets monkeypatched! See ReactDOMForm for more info. - form: false, - h1: false, - h2: false, - h3: false, - h4: false, - h5: false, - h6: false, - header: false, - hr: true, - i: false, - iframe: false, - img: true, - input: true, - label: false, - legend: false, - li: false, - line: false, - nav: false, - object: false, - ol: false, - optgroup: false, - option: false, - p: false, - param: true, - pre: false, - select: false, - small: false, - source: false, - span: false, - sub: false, - sup: false, - strong: false, - table: false, - tbody: false, - td: false, - textarea: false, - tfoot: false, - th: false, - thead: false, - time: false, - title: false, - tr: false, - u: false, - ul: false, - video: false, - wbr: false, - - // SVG - circle: false, - g: false, - path: false, - polyline: false, - rect: false, - svg: false, - text: false -}, createDOMComponentClass); - -var injection = { - injectComponentClasses: function(componentClasses) { - mergeInto(ReactDOM, componentClasses); - } -}; - -ReactDOM.injection = injection; - -module.exports = ReactDOM; - -},{"./ReactNativeComponent":17,"./mergeInto":18,"./objMapKeyVal":19}],5:[function(require,module,exports){ +},{"./ReactCurrentOwner":24,"./ReactDOMIDOperations":27,"./ReactID":35,"./ReactMount":38,"./ReactOwner":42,"./ReactReconcileTransaction":45,"./ReactUpdates":48,"./invariant":75,"./keyMirror":78,"./merge":81}],23:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * @@ -1458,661 +3520,909 @@ module.exports = ReactDOM; * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule ReactMount + * @providesModule ReactCompositeComponent */ "use strict"; -var ReactEvent = require("./ReactEvent"); -var ReactInstanceHandles = require("./ReactInstanceHandles"); -var ReactEventTopLevelCallback = require("./ReactEventTopLevelCallback"); - -var $ = require("./$"); - -var globalMountPointCounter = 0; - -/** Mapping from reactRoot DOM ID to React component instance. */ -var instanceByReactRootID = {}; +var ReactComponent = require("./ReactComponent"); +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactOwner = require("./ReactOwner"); +var ReactPropTransferer = require("./ReactPropTransferer"); +var ReactUpdates = require("./ReactUpdates"); -/** Mapping from reactRoot DOM ID to `container` nodes. */ -var containersByReactRootID = {}; +var invariant = require("./invariant"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); +var mixInto = require("./mixInto"); /** - * @param {DOMElement} container DOM element that may contain a React component. - * @return {?string} A "reactRoot" ID, if a React component is rendered. + * Policies that describe methods in `ReactCompositeComponentInterface`. */ -function getReactRootID(container) { - return container.firstChild && container.firstChild.id; -} +var SpecPolicy = keyMirror({ + /** + * These methods may be defined only once by the class specification or mixin. + */ + DEFINE_ONCE: null, + /** + * These methods may be defined by both the class specification and mixins. + * Subsequent definitions will be chained. These methods must return void. + */ + DEFINE_MANY: null, + /** + * These methods are overriding the base ReactCompositeComponent class. + */ + OVERRIDE_BASE: null +}); /** - * Mounting is the process of initializing a React component by creatings its - * representative DOM elements and inserting them into a supplied `container`. - * Any prior content inside `container` is destroyed in the process. + * Composite components are higher-level components that compose other composite + * or native components. * - * ReactMount.renderComponent(component, $('container')); + * To create a new type of `ReactCompositeComponent`, pass a specification of + * your new class to `React.createClass`. The only requirement of your class + * specification is that you implement a `render` method. * - *
<-- Supplied `container`. - *
<-- Rendered reactRoot of React component. - * // ... - *
- *
+ * var MyComponent = React.createClass({ + * render: function() { + * return
Hello World
; + * } + * }); * - * Inside of `container`, the first element rendered is the "reactRoot". - */ -var ReactMount = { - - /** Time spent generating markup. */ - totalInstantiationTime: 0, - - /** Time spent inserting markup into the DOM. */ - totalInjectionTime: 0, - - /** Whether support for touch events should be initialized. */ - useTouchEvents: false, - - /** - * This is a hook provided to support rendering React components while - * ensuring that the apparent scroll position of its `container` does not - * change. - * - * @param {DOMElement} container The `container` being rendered into. - * @param {function} renderCallback This must be called once to do the render. - */ - scrollMonitor: function(container, renderCallback) { - renderCallback(); - }, + * The class specification supports a specific protocol of methods that have + * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for + * more the comprehensive protocol. Any other properties and methods in the + * class specification will available on the prototype. + * + * @interface ReactCompositeComponentInterface + * @internal + */ +var ReactCompositeComponentInterface = { /** - * Ensures tht the top-level event delegation listener is set up. This will be - * invoked some time before the first time any React component is rendered. + * An array of Mixin objects to include when defining your component. * - * @param {object} TopLevelCallbackCreator - * @private + * @type {array} + * @optional */ - prepareTopLevelEvents: function(TopLevelCallbackCreator) { - ReactEvent.ensureListening( - ReactMount.useTouchEvents, - TopLevelCallbackCreator - ); - }, + mixins: SpecPolicy.DEFINE_MANY, /** - * Renders a React component into the DOM in the supplied `container`. - * - * If the React component was previously rendered into `container`, this will - * perform an update on it and only mutate the DOM as necessary to reflect the - * latest React component. + * Definition of prop types for this component. * - * @param {ReactComponent} nextComponent Component instance to render. - * @param {DOMElement} container DOM element to render into. - * @return {ReactComponent} Component instance rendered in `container`. + * @type {object} + * @optional */ - renderComponent: function(nextComponent, container) { - var prevComponent = instanceByReactRootID[getReactRootID(container)]; - if (prevComponent) { - var nextProps = nextComponent.props; - ReactMount.scrollMonitor(container, function() { - prevComponent.replaceProps(nextProps); - }); - return prevComponent; - } + propTypes: SpecPolicy.DEFINE_ONCE, - ReactMount.prepareTopLevelEvents(ReactEventTopLevelCallback); - var reactRootID = ReactMount.registerContainer(container); - instanceByReactRootID[reactRootID] = nextComponent; - nextComponent.mountComponentIntoNode(reactRootID, container); - return nextComponent; - }, + + // ==== Definition methods ==== /** - * Creates a function that accepts a `container` and renders the supplied - * React component instance into it. + * Invoked when the component is mounted. Values in the mapping will be set on + * `this.props` if that prop is not specified (i.e. using an `in` check). * - * var renderInto = ReactMount.createComponentRenderer(component); - * // ... - * var component = renderInto($('container')); + * This method is invoked before `getInitialState` and therefore cannot rely + * on `this.state` or use `this.setState`. * - * @param {ReactComponent} component Component instance to render. - * @return {function(DOMElement): ReactComponent} + * @return {object} + * @optional */ - createComponentRenderer: function(component) { - return function(container) { - return ReactMount.renderComponent(component, container); - }; - }, + getDefaultProps: SpecPolicy.DEFINE_ONCE, /** - * Constructs a component instance of `constructor` with `initialProps` and - * renders it into the supplied `container`. + * Invoked once before the component is mounted. The return value will be used + * as the initial value of `this.state`. * - * @param {function} constructor React component constructor. - * @param {?object} props Initial props of the component instance. - * @param {DOMElement} container DOM element to render into. - * @return {ReactComponent} Component instance rendered in `container`. + * getInitialState: function() { + * return { + * isOn: false, + * fooBaz: new BazFoo() + * } + * } + * + * @return {object} + * @optional */ - constructAndRenderComponent: function(constructor, props, container) { - return ReactMount.renderComponent(constructor(props), container); - }, + getInitialState: SpecPolicy.DEFINE_ONCE, /** - * Constructs a component instance of `constructor` with `initialProps` and - * renders it into a container node identified by supplied `id`. + * Uses props from `this.props` and state from `this.state` to render the + * structure of the component. * - * @param {function} componentConstructor React component constructor - * @param {?object} props Initial props of the component instance. - * @param {string} id ID of the DOM element to render into. - * @return {ReactComponent} Component instance rendered in the container node. + * No guarantees are made about when or how often this method is invoked, so + * it must not have side effects. + * + * render: function() { + * var name = this.props.name; + * return
Hello, {name}!
; + * } + * + * @return {ReactComponent} + * @nosideeffects + * @required */ - constructAndRenderComponentByID: function(constructor, props, id) { - return ReactMount.constructAndRenderComponent(constructor, props, $(id)); - }, + render: SpecPolicy.DEFINE_ONCE, + + + + // ==== Delegate methods ==== /** - * Registers a container node into which React components will be rendered. - * This also creates the "reatRoot" ID that will be assigned to the element - * rendered within. + * Invoked when the component is initially created and about to be mounted. + * This may have side effects, but any external subscriptions or data created + * by this method must be cleaned up in `componentWillUnmount`. * - * @param {DOMElement} container DOM element to register as a container. - * @return {string} The "reactRoot" ID of elements rendered within. + * @optional */ - registerContainer: function(container) { - var reactRootID = getReactRootID(container); - if (reactRootID) { - // If one exists, make sure it is a valid "reactRoot" ID. - reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID); - } - if (!reactRootID) { - // No valid "reactRoot" ID found, create one. - reactRootID = ReactInstanceHandles.getReactRootID( - globalMountPointCounter++ - ); - } - containersByReactRootID[reactRootID] = container; - return reactRootID; - }, + componentWillMount: SpecPolicy.DEFINE_MANY, /** - * Unmounts and destroys the React component rendered in the `container`. + * Invoked when the component has been mounted and has a DOM representation. + * However, there is no guarantee that the DOM node is in the document. * - * @param {DOMElement} container DOM element containing a React component. + * Use this as an opportunity to operate on the DOM when the component has + * been mounted (initialized and rendered) for the first time. + * + * @param {DOMElement} rootNode DOM element representing the component. + * @optional */ - unmountAndReleaseReactRootNode: function(container) { - var reactRootID = getReactRootID(container); - var component = instanceByReactRootID[reactRootID]; - // TODO: Consider throwing if no `component` was found. - component.unmountComponentFromNode(container); - delete instanceByReactRootID[reactRootID]; - delete containersByReactRootID[reactRootID]; - }, + componentDidMount: SpecPolicy.DEFINE_MANY, /** - * Finds the container DOM element that contains React component to which the - * supplied DOM `id` belongs. + * Invoked before the component receives new props. * - * @param {string} id The ID of an element rendered by a React component. - * @return {?DOMElement} DOM element that contains the `id`. + * Use this as an opportunity to react to a prop transition by updating the + * state using `this.setState`. Current props are accessed via `this.props`. + * + * componentWillReceiveProps: function(nextProps) { + * this.setState({ + * likesIncreasing: nextProps.likeCount > this.props.likeCount + * }); + * } + * + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop + * transition may cause a state change, but the opposite is not true. If you + * need it, you are probably looking for `componentWillUpdate`. + * + * @param {object} nextProps + * @optional */ - findReactContainerForID: function(id) { - var reatRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id); - // TODO: Consider throwing if `id` is not a valid React element ID. - return containersByReactRootID[reatRootID]; - }, + componentWillReceiveProps: SpecPolicy.DEFINE_MANY, /** - * Given the ID of a DOM node rendered by a React component, finds the root - * DOM node of the React component. + * Invoked while deciding if the component should be updated as a result of + * receiving new props and state. * - * @param {string} id ID of a DOM node in the React component. - * @return {?DOMElement} Root DOM node of the React component. + * Use this as an opportunity to `return false` when you're certain that the + * transition to the new props and state will not require a component update. + * + * shouldComponentUpdate: function(nextProps, nextState) { + * return !equal(nextProps, this.props) || !equal(nextState, this.state); + * } + * + * @param {object} nextProps + * @param {?object} nextState + * @return {boolean} True if the component should update. + * @optional */ - findReactRenderedDOMNodeSlow: function(id) { - var reactRoot = ReactMount.findReactContainerForID(id); - return ReactInstanceHandles.findComponentRoot(reactRoot, id); - } - -}; - -module.exports = ReactMount; - -})() -},{"./ReactEvent":20,"./ReactInstanceHandles":21,"./ReactEventTopLevelCallback":22,"./$":23}],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 ReactDefaultInjection - */ - -"use strict"; - -var ReactDOM = require("./ReactDOM"); -var ReactDOMForm = require("./ReactDOMForm"); - -var DefaultEventPluginOrder = require("./DefaultEventPluginOrder"); -var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin"); -var EventPluginHub = require("./EventPluginHub"); -var ReactInstanceHandles = require("./ReactInstanceHandles"); -var SimpleEventPlugin = require("./SimpleEventPlugin"); + shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, -function inject() { /** - * Inject module for resolving DOM hierarchy and plugin ordering. + * Invoked when the component is about to update due to a transition from + * `this.props` and `this.state` to `nextProps` and `nextState`. + * + * Use this as an opportunity to perform preparation before an update occurs. + * + * NOTE: You **cannot** use `this.setState()` in this method. + * + * @param {object} nextProps + * @param {?object} nextState + * @param {ReactReconcileTransaction} transaction + * @optional */ - EventPluginHub.injection.injectEventPluginOrder(DefaultEventPluginOrder); - EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles); + componentWillUpdate: SpecPolicy.DEFINE_MANY, /** - * Two important event plugins included by default (without having to require - * them). - */ - EventPluginHub.injection.injectEventPluginsByName({ - 'SimpleEventPlugin': SimpleEventPlugin, - 'EnterLeaveEventPlugin': EnterLeaveEventPlugin - }); - - /* - * This is a bit of a hack. We need to override the
element - * to be a composite component because IE8 does not bubble or capture - * submit to the top level. In order to make this work with our - * dependency graph we need to inject it here. + * Invoked when the component's DOM representation has been updated. + * + * Use this as an opportunity to operate on the DOM when the component has + * been updated. + * + * @param {object} prevProps + * @param {?object} prevState + * @param {DOMElement} rootNode DOM element representing the component. + * @optional */ - ReactDOM.injection.injectComponentClasses({ - form: ReactDOMForm - }); -} - -module.exports = { - inject: inject -}; + componentDidUpdate: SpecPolicy.DEFINE_MANY, -},{"./ReactDOM":4,"./ReactDOMForm":24,"./DefaultEventPluginOrder":25,"./EnterLeaveEventPlugin":26,"./EventPluginHub":27,"./ReactInstanceHandles":21,"./SimpleEventPlugin":28}],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 ReactCurrentOwner - */ + /** + * Invoked when the component is about to be removed from its parent and have + * its DOM representation destroyed. + * + * Use this as an opportunity to deallocate any external resources. + * + * NOTE: There is no `componentDidUnmount` since your component will have been + * destroyed by that point. + * + * @optional + */ + componentWillUnmount: SpecPolicy.DEFINE_MANY, -"use strict"; -/** - * Keeps track of the current owner. - * - * The current owner is the component who should own any components that are - * currently being constructed. - */ -var ReactCurrentOwner = { + + // ==== Advanced methods ==== /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction * @internal - * @type {ReactComponent} + * @overridable */ - current: null + updateComponent: SpecPolicy.OVERRIDE_BASE }; -module.exports = ReactCurrentOwner; - -},{}],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. + * Mapping from class specification keys to special processing functions. * - * @providesModule invariant + * Although these are declared in the specification when defining classes + * using `React.createClass`, they will not be on the component's prototype. */ +var RESERVED_SPEC_KEYS = { + displayName: function(Constructor, displayName) { + Constructor.displayName = displayName; + }, + mixins: function(Constructor, mixins) { + if (mixins) { + for (var i = 0; i < mixins.length; i++) { + mixSpecIntoComponent(Constructor, mixins[i]); + } + } + }, + propTypes: function(Constructor, propTypes) { + Constructor.propTypes = propTypes; + } +}; -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf style format and arguments to provide information about - * what broke and what you were expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ +function validateMethodOverride(proto, name) { + var specPolicy = ReactCompositeComponentInterface[name]; -function invariant(condition) { - if (!condition) { - throw new Error('Invariant Violation'); + // Disallow overriding of base class methods unless explicitly allowed. + if (ReactCompositeComponentMixin.hasOwnProperty(name)) { + invariant( + specPolicy === SpecPolicy.OVERRIDE_BASE, + 'ReactCompositeComponentInterface: You are attempting to override ' + + '`%s` from your class specification. Ensure that your method names ' + + 'do not overlap with React methods.', + name + ); + } + + // Disallow defining methods more than once unless explicitly allowed. + if (proto.hasOwnProperty(name)) { + invariant( + specPolicy === SpecPolicy.DEFINE_MANY, + 'ReactCompositeComponentInterface: You are attempting to define ' + + '`%s` on your component more than once. This conflict may be due ' + + 'to a mixin.', + name + ); } } -module.exports = invariant; -if (true) { - var invariantDev = function(condition, format, a, b, c, d, e, f) { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } +function validateLifeCycleOnReplaceState(instance) { + var compositeLifeCycleState = instance._compositeLifeCycleState; + invariant( + instance.isMounted() || + compositeLifeCycleState === CompositeLifeCycle.MOUNTING, + 'replaceState(...): Can only update a mounted or mounting component.' + ); + invariant( + compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && + compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, + 'replaceState(...): Cannot update while unmounting component or during ' + + 'an existing state transition (such as within `render`).' + ); +} - if (!condition) { - var args = [a, b, c, d, e, f]; - var argIndex = 0; - throw new Error( - 'Invariant Violation: ' + - format.replace(/%s/g, function() { return args[argIndex++]; }) - ); +/** + * Custom version of `mixInto` which handles policy validation and reserved + * specification keys when building `ReactCompositeComponent` classses. + */ +function mixSpecIntoComponent(Constructor, spec) { + var proto = Constructor.prototype; + for (var name in spec) { + var property = spec[name]; + if (!spec.hasOwnProperty(name) || !property) { + continue; } - }; + validateMethodOverride(proto, name); - module.exports = invariantDev; + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { + RESERVED_SPEC_KEYS[name](Constructor, property); + } else { + // Setup methods on prototype: + // The following member methods should not be automatically bound: + // 1. Expected ReactCompositeComponent methods (in the "interface"). + // 2. Overridden methods (that were mixed in). + var isCompositeComponentMethod = name in ReactCompositeComponentInterface; + var isInherited = name in proto; + var markedDontBind = property.__reactDontBind; + var isFunction = typeof property === 'function'; + var shouldAutoBind = + isFunction && + !isCompositeComponentMethod && + !isInherited && + !markedDontBind; + + if (shouldAutoBind) { + if (!proto.__reactAutoBindMap) { + proto.__reactAutoBindMap = {}; + } + proto.__reactAutoBindMap[name] = property; + proto[name] = property; + } else { + if (isInherited) { + // For methods which are defined more than once, call the existing + // methods before calling the new property. + proto[name] = createChainedFunction(proto[name], property); + } else { + proto[name] = property; + } + } + } + } } -},{}],13:[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. + * Creates a function that invokes two functions and ignores their return vales. * - * @providesModule mixInto + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private */ +function createChainedFunction(one, two) { + return function chainedFunction() { + one.apply(this, arguments); + two.apply(this, arguments); + }; +} -"use strict"; +/** + * `ReactCompositeComponent` maintains an auxiliary life cycle state in + * `this._compositeLifeCycleState` (which can be null). + * + * This is different from the life cycle state maintained by `ReactComponent` in + * `this._lifeCycleState`. The following diagram shows how the states overlap in + * time. There are times when the CompositeLifeCycle is null - at those times it + * is only meaningful to look at ComponentLifeCycle alone. + * + * Top Row: ReactComponent.ComponentLifeCycle + * Low Row: ReactComponent.CompositeLifeCycle + * + * +-------+------------------------------------------------------+--------+ + * | UN | MOUNTED | UN | + * |MOUNTED| | MOUNTED| + * +-------+------------------------------------------------------+--------+ + * | ^--------+ +------+ +------+ +------+ +--------^ | + * | | | | | | | | | | | | + * | 0--|MOUNTING|-0-|RECEIV|-0-|RECEIV|-0-|RECEIV|-0-| UN |--->0 | + * | | | |PROPS | | PROPS| | STATE| |MOUNTING| | + * | | | | | | | | | | | | + * | | | | | | | | | | | | + * | +--------+ +------+ +------+ +------+ +--------+ | + * | | | | + * +-------+------------------------------------------------------+--------+ + */ +var CompositeLifeCycle = keyMirror({ + /** + * Components in the process of being mounted respond to state changes + * differently. + */ + MOUNTING: null, + /** + * Components in the process of being unmounted are guarded against state + * changes. + */ + UNMOUNTING: null, + /** + * Components that are mounted and receiving new props respond to state + * changes differently. + */ + RECEIVING_PROPS: null, + /** + * Components that are mounted and receiving new state are guarded against + * additional state changes. + */ + RECEIVING_STATE: null +}); /** - * Simply copies properties to the prototype. + * @lends {ReactCompositeComponent.prototype} */ -var mixInto = function(constructor, methodBag) { - var methodName; - for (methodName in methodBag) { - if (!methodBag.hasOwnProperty(methodName)) { - continue; +var ReactCompositeComponentMixin = { + + /** + * Base constructor for all composite component. + * + * @param {?object} initialProps + * @param {*} children + * @final + * @internal + */ + construct: function(initialProps, children) { + // Children can be either an array or more than one argument + ReactComponent.Mixin.construct.apply(this, arguments); + this.state = null; + this._pendingState = null; + this._compositeLifeCycleState = null; + }, + + /** + * Checks whether or not this composite component is mounted. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function() { + return ReactComponent.Mixin.isMounted.call(this) && + this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING; + }, + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @final + * @internal + */ + mountComponent: function(rootID, transaction) { + ReactComponent.Mixin.mountComponent.call(this, rootID, transaction); + this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING; + + this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null; + this._processProps(this.props); + + if (this.__reactAutoBindMap) { + this._bindAutoBindMethods(); } - constructor.prototype[methodName] = methodBag[methodName]; - } -}; -module.exports = mixInto; + this.state = this.getInitialState ? this.getInitialState() : null; + this._pendingState = null; + this._pendingForceUpdate = false; + + if (this.componentWillMount) { + this.componentWillMount(); + // When mounting, calls to `setState` by `componentWillMount` will set + // `this._pendingState` without triggering a re-render. + if (this._pendingState) { + this.state = this._pendingState; + this._pendingState = null; + } + } + + this._renderedComponent = this._renderValidatedComponent(); + + // Done with mounting, `setState` will now trigger UI changes. + this._compositeLifeCycleState = null; + var markup = this._renderedComponent.mountComponent(rootID, transaction); + if (this.componentDidMount) { + transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount); + } + return markup; + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * @final + * @internal + */ + unmountComponent: function() { + this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING; + if (this.componentWillUnmount) { + this.componentWillUnmount(); + } + this._compositeLifeCycleState = null; -},{}],14:[function(require,module,exports){ -(function(){/** - * 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 ExecutionEnvironment - */ + this._defaultProps = null; -/*jslint evil: true */ + ReactComponent.Mixin.unmountComponent.call(this); + this._renderedComponent.unmountComponent(); + this._renderedComponent = null; -"use strict"; + if (this.refs) { + this.refs = null; + } -var canUseDOM = typeof window !== 'undefined'; + // Some existing components rely on this.props even after they've been + // destroyed (in event handlers). + // TODO: this.props = null; + // TODO: this.state = null; + }, -/** - * Simple, lightweight module assisting with the detection and context of - * Worker. Helps avoid circular dependencies and allows code to reason about - * whether or not they are in a Worker, even if they never include the main - * `ReactWorker` dependency. - */ -var ExecutionEnvironment = { + /** + * Sets a subset of the state. Always use this or `replaceState` to mutate + * state. You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * There is no guarantee that calls to `setState` will run synchronously, + * as they may eventually be batched together. You can provide an optional + * callback that will be executed when the call to setState is actually + * completed. + * + * @param {object} partialState Next partial state to be merged with state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ + setState: function(partialState, callback) { + // Merge with `_pendingState` if it exists, otherwise with existing state. + this.replaceState( + merge(this._pendingState || this.state, partialState), + callback + ); + }, - canUseDOM: canUseDOM, + /** + * Replaces all of the state. Always use this or `setState` to mutate state. + * You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * @param {object} completeState Next state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ + replaceState: function(completeState, callback) { + validateLifeCycleOnReplaceState(this); + this._pendingState = completeState; + ReactUpdates.enqueueUpdate(this, callback); + }, - canUseWorkers: typeof Worker !== 'undefined', + /** + * Processes props by setting default values for unspecified props and + * asserting that the props are valid. + * + * @param {object} props + * @private + */ + _processProps: function(props) { + var propName; + var defaultProps = this._defaultProps; + for (propName in defaultProps) { + if (!(propName in props)) { + props[propName] = defaultProps[propName]; + } + } + var propTypes = this.constructor.propTypes; + if (propTypes) { + var componentName = this.constructor.displayName; + for (propName in propTypes) { + var checkProp = propTypes[propName]; + if (checkProp) { + checkProp(props, propName, componentName); + } + } + } + }, - isInWorker: !canUseDOM, // For now, this is true - might change in the future. + performUpdateIfNecessary: function() { + var compositeLifeCycleState = this._compositeLifeCycleState; + // Do not trigger a state transition if we are in the middle of mounting or + // receiving props because both of those will already be doing this. + if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING || + compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) { + return; + } + ReactComponent.Mixin.performUpdateIfNecessary.call(this); + }, - global: new Function('return this;')() + /** + * If any of `_pendingProps`, `_pendingState`, or `_pendingForceUpdate` is + * set, update the component. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + _performUpdateIfNecessary: function(transaction) { + if (this._pendingProps == null && + this._pendingState == null && + !this._pendingForceUpdate) { + return; + } -}; + var nextProps = this.props; + if (this._pendingProps != null) { + nextProps = this._pendingProps; + this._processProps(nextProps); + this._pendingProps = null; -module.exports = ExecutionEnvironment; + this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS; + if (this.componentWillReceiveProps) { + this.componentWillReceiveProps(nextProps, transaction); + } + } -})() -},{}],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. - * - * @providesModule objMapKeyVal - */ + this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; -"use strict"; + var nextState = this._pendingState || this.state; + this._pendingState = null; -/** - * Behaves the same as `objMap` but invokes func with the key first, and value - * second. Use `objMap` unless you need this special case. - * Invokes func as: - * - * func(key, value, iteration) - * - * @param {?object} obj Object to map keys over - * @param {!function} func Invoked for each key/val pair. - * @param {?*} context - * @return {?object} Result of mapping or null if obj is falsey - */ -function objMapKeyVal(obj, func, context) { - if (!obj) { - return null; - } - var i = 0; - var ret = {}; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = func.call(context, key, obj[key], i++); + if (this._pendingForceUpdate || + !this.shouldComponentUpdate || + this.shouldComponentUpdate(nextProps, nextState)) { + this._pendingForceUpdate = false; + // Will set `this.props` and `this.state`. + this._performComponentUpdate(nextProps, nextState, transaction); + } else { + // If it's determined that a component should not update, we still want + // to set props and state. + this.props = nextProps; + this.state = nextState; } - } - return ret; -} -module.exports = objMapKeyVal; + this._compositeLifeCycleState = null; + }, -},{}],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 ReactOwner - */ + /** + * Merges new props and state, notifies delegate methods of update and + * performs update. + * + * @param {object} nextProps Next object to set as properties. + * @param {?object} nextState Next object to set as state. + * @param {ReactReconcileTransaction} transaction + * @private + */ + _performComponentUpdate: function(nextProps, nextState, transaction) { + var prevProps = this.props; + var prevState = this.state; -"use strict"; + if (this.componentWillUpdate) { + this.componentWillUpdate(nextProps, nextState, transaction); + } -var invariant = require("./invariant"); + this.props = nextProps; + this.state = nextState; -/** - * ReactOwners are capable of storing references to owned components. - * - * All components are capable of //being// referenced by owner components, but - * only ReactOwner components are capable of //referencing// owned components. - * The named reference is known as a "ref". - * - * Refs are available when mounted and updated during reconciliation. - * - * var MyComponent = React.createClass({ - * render: function() { - * return ( - *
- * - *
- * ); - * }, - * handleClick: React.autoBind(function() { - * this.refs.custom.handleClick(); - * }), - * componentDidMount: function() { - * this.refs.custom.initialize(); - * } - * }); - * - * Refs should rarely be used. When refs are used, they should only be done to - * control data that is not handled by React's data flow. - * - * @class ReactOwner - */ -var ReactOwner = { + this.updateComponent(transaction, prevProps, prevState); + + if (this.componentDidUpdate) { + transaction.getReactOnDOMReady().enqueue( + this, + this.componentDidUpdate.bind(this, prevProps, prevState) + ); + } + }, + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @param {object} prevProps + * @param {?object} prevState + * @internal + * @overridable + */ + updateComponent: function(transaction, prevProps, prevState) { + ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps); + var currentComponent = this._renderedComponent; + var nextComponent = this._renderValidatedComponent(); + if (currentComponent.constructor === nextComponent.constructor) { + currentComponent.receiveProps(nextComponent.props, transaction); + } else { + // These two IDs are actually the same! But nothing should rely on that. + var thisID = this._rootNodeID; + var currentComponentID = currentComponent._rootNodeID; + currentComponent.unmountComponent(); + var nextMarkup = nextComponent.mountComponent(thisID, transaction); + ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( + currentComponentID, + nextMarkup + ); + this._renderedComponent = nextComponent; + } + }, /** - * @param {?object} object - * @return {boolean} True if `object` is a valid owner. + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldUpdateComponent`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {?function} callback Called after update is complete. * @final + * @protected */ - isValidOwner: function(object) { - return !!( - object && - typeof object.attachRef === 'function' && - typeof object.detachRef === 'function' + forceUpdate: function(callback) { + var compositeLifeCycleState = this._compositeLifeCycleState; + invariant( + this.isMounted() || + compositeLifeCycleState === CompositeLifeCycle.MOUNTING, + 'forceUpdate(...): Can only force an update on mounted or mounting ' + + 'components.' + ); + invariant( + compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && + compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, + 'forceUpdate(...): Cannot force an update while unmounting component ' + + 'or during an existing state transition (such as within `render`).' ); + this._pendingForceUpdate = true; + ReactUpdates.enqueueUpdate(this, callback); }, /** - * Adds a component by ref to an owner component. - * - * @param {ReactComponent} component Component to reference. - * @param {string} ref Name by which to refer to the component. - * @param {ReactOwner} owner Component on which to record the ref. - * @final - * @internal + * @private */ - addComponentAsRefTo: function(component, ref, owner) { + _renderValidatedComponent: function() { + var renderedComponent; + ReactCurrentOwner.current = this; + try { + renderedComponent = this.render(); + } catch (error) { + // IE8 requires `catch` in order to use `finally`. + throw error; + } finally { + ReactCurrentOwner.current = null; + } invariant( - ReactOwner.isValidOwner(owner), - 'addComponentAsRefTo(...): Only a ReactOwner can have refs.' + ReactComponent.isValidComponent(renderedComponent), + '%s.render(): A valid ReactComponent must be returned.', + this.constructor.displayName || 'ReactCompositeComponent' ); - owner.attachRef(ref, component); + return renderedComponent; }, /** - * Removes a component by ref from an owner component. + * @private + */ + _bindAutoBindMethods: function() { + for (var autoBindKey in this.__reactAutoBindMap) { + if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { + continue; + } + var method = this.__reactAutoBindMap[autoBindKey]; + this[autoBindKey] = this._bindAutoBindMethod(method); + } + }, + + /** + * Binds a method to the component. * - * @param {ReactComponent} component Component to dereference. - * @param {string} ref Name of the ref to remove. - * @param {ReactOwner} owner Component on which the ref is recorded. - * @final - * @internal + * @param {function} method Method to be bound. + * @private */ - removeComponentAsRefFrom: function(component, ref, owner) { + _bindAutoBindMethod: function(method) { + var component = this; + var boundMethod = function() { + return method.apply(component, arguments); + }; + if (true) { + var componentName = component.constructor.displayName; + var _bind = boundMethod.bind; + boundMethod.bind = function(newThis) { + // User is trying to bind() an autobound method; we effectively will + // ignore the value of "this" that the user is trying to use, so + // let's warn. + if (newThis !== component) { + console.warn( + 'bind(): React component methods may only be bound to the ' + + 'component instance. See ' + componentName + ); + } else if (arguments.length === 1) { + console.warn( + 'bind(): You are binding a component method to the component. ' + + 'React does this for you automatically in a high-performance ' + + 'way, so you can safely remove this call. See ' + componentName + ); + return boundMethod; + } + return _bind.apply(boundMethod, arguments); + }; + } + return boundMethod; + } +}; + +var ReactCompositeComponentBase = function() {}; +mixInto(ReactCompositeComponentBase, ReactComponent.Mixin); +mixInto(ReactCompositeComponentBase, ReactOwner.Mixin); +mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin); +mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin); + +/** + * Module for creating composite components. + * + * @class ReactCompositeComponent + * @extends ReactComponent + * @extends ReactOwner + * @extends ReactPropTransferer + */ +var ReactCompositeComponent = { + + LifeCycle: CompositeLifeCycle, + + Base: ReactCompositeComponentBase, + + /** + * Creates a composite component class given a class specification. + * + * @param {object} spec Class specification (which must define `render`). + * @return {function} Component constructor function. + * @public + */ + createClass: function(spec) { + var Constructor = function() {}; + Constructor.prototype = new ReactCompositeComponentBase(); + Constructor.prototype.constructor = Constructor; + mixSpecIntoComponent(Constructor, spec); invariant( - ReactOwner.isValidOwner(owner), - 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs.' + Constructor.prototype.render, + 'createClass(...): Class specification must implement a `render` method.' ); - // Check that `component` is still the current ref because we do not want to - // detach the ref if another component stole it. - if (owner.refs[ref] === component) { - owner.detachRef(ref); + // Reduce time spent doing lookups by setting these on the prototype. + for (var methodName in ReactCompositeComponentInterface) { + if (!Constructor.prototype[methodName]) { + Constructor.prototype[methodName] = null; + } } + + var ConvenienceConstructor = function(props, children) { + var instance = new Constructor(); + instance.construct.apply(instance, arguments); + return instance; + }; + ConvenienceConstructor.componentConstructor = Constructor; + ConvenienceConstructor.originalSpec = spec; + return ConvenienceConstructor; }, /** - * A ReactComponent must mix this in to have refs. + * TODO: Delete this when all callers have been updated to rely on this + * behavior being the default. * - * @lends {ReactOwner.prototype} + * Backwards compatible stub for what is now the default behavior. + * @param {function} method Method to be bound. + * @public */ - Mixin: { - - /** - * Lazily allocates the refs object and stores `component` as `ref`. - * - * @param {string} ref Reference name. - * @param {component} component Component to store as `ref`. - * @final - * @private - */ - attachRef: function(ref, component) { - invariant( - component.isOwnedBy(this), - 'attachRef(%s, ...): Only a component\'s owner can store a ref to it.', - ref + autoBind: function(method) { + if (true) { + console.warn( + 'React.autoBind() is now deprecated. All React component methods ' + + 'are auto bound by default, so React.autoBind() is a no-op. It ' + + 'will be removed in the next version of React' ); - var refs = this.refs || (this.refs = {}); - refs[ref] = component; - }, - - /** - * Detaches a reference name. - * - * @param {string} ref Name to dereference. - * @final - * @private - */ - detachRef: function(ref) { - delete this.refs[ref]; } - + return method; } - }; -module.exports = ReactOwner; +module.exports = ReactCompositeComponent; -},{"./invariant":10}],9:[function(require,module,exports){ +})() +},{"./ReactComponent":22,"./ReactCurrentOwner":24,"./ReactOwner":42,"./ReactPropTransferer":43,"./ReactUpdates":48,"./invariant":75,"./keyMirror":78,"./merge":81,"./mixInto":84}],24:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -2128,107 +4438,32 @@ module.exports = ReactOwner; * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule ReactPropTransferer + * @providesModule ReactCurrentOwner */ "use strict"; -var emptyFunction = require("./emptyFunction"); -var joinClasses = require("./joinClasses"); -var merge = require("./merge"); - /** - * Creates a transfer strategy that will merge prop values using the supplied - * `mergeStrategy`. If a prop was previously unset, this just sets it. + * Keeps track of the current owner. * - * @param {function} mergeStrategy - * @return {function} - */ -function createTransferStrategy(mergeStrategy) { - return function(props, key, value) { - if (!props.hasOwnProperty(key)) { - props[key] = value; - } else { - props[key] = mergeStrategy(props[key], value); - } - }; -} - -/** - * Transfer strategies dictate how props are transferred by `transferPropsTo`. - */ -var TransferStrategies = { - /** - * Never transfer the `ref` prop. - */ - ref: emptyFunction, - /** - * Transfer the `className` prop by merging them. - */ - className: createTransferStrategy(joinClasses), - /** - * Transfer the `style` prop (which is an object) by merging them. - */ - style: createTransferStrategy(merge) -}; - -/** - * ReactPropTransferer are capable of transferring props to another component - * using a `transferPropsTo` method. + * The current owner is the component who should own any components that are + * currently being constructed. * - * @class ReactPropTransferer + * The depth indicate how many composite components are above this render level. */ -var ReactPropTransferer = { - - TransferStrategies: TransferStrategies, - - /** - * @lends {ReactPropTransferer.prototype} - */ - Mixin: { - - /** - * Transfer props from this component to a target component. - * - * Props that do not have an explicit transfer strategy will be transferred - * only if the target component does not already have the prop set. - * - * This is usually used to pass down props to a returned root component. - * - * @param {ReactComponent} component Component receiving the properties. - * @return {ReactComponent} The supplied `component`. - * @final - * @protected - */ - transferPropsTo: function(component) { - var props = {}; - for (var thatKey in component.props) { - if (component.props.hasOwnProperty(thatKey)) { - props[thatKey] = component.props[thatKey]; - } - } - for (var thisKey in this.props) { - if (!this.props.hasOwnProperty(thisKey)) { - continue; - } - var transferStrategy = TransferStrategies[thisKey]; - if (transferStrategy) { - transferStrategy(props, thisKey, this.props[thisKey]); - } else if (!props.hasOwnProperty(thisKey)) { - props[thisKey] = this.props[thisKey]; - } - } - component.props = props; - return component; - } +var ReactCurrentOwner = { - } + /** + * @internal + * @type {ReactComponent} + */ + current: null }; -module.exports = ReactPropTransferer; +module.exports = ReactCurrentOwner; -},{"./emptyFunction":29,"./joinClasses":30,"./merge":12}],11:[function(require,module,exports){ +},{}],25:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -2244,49 +4479,186 @@ module.exports = ReactPropTransferer; * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule keyMirror + * @providesModule ReactDOM + * @typechecks static-only */ "use strict"; -var throwIf = require("./throwIf"); +var ReactNativeComponent = require("./ReactNativeComponent"); -var NOT_OBJECT_ERROR = 'NOT_OBJECT_ERROR'; -if (true) { - NOT_OBJECT_ERROR = 'keyMirror only works on objects'; +var mergeInto = require("./mergeInto"); +var objMapKeyVal = require("./objMapKeyVal"); + +/** + * Creates a new React class that is idempotent and capable of containing other + * React components. It accepts event listeners and DOM properties that are + * valid according to `DOMProperty`. + * + * - Event listeners: `onClick`, `onMouseDown`, etc. + * - DOM properties: `className`, `name`, `title`, etc. + * + * The `style` property functions differently from the DOM API. It accepts an + * object mapping of style properties to values. + * + * @param {string} tag Tag name (e.g. `div`). + * @param {boolean} omitClose True if the close tag should be omitted. + * @private + */ +function createDOMComponentClass(tag, omitClose) { + var Constructor = function() {}; + Constructor.prototype = new ReactNativeComponent(tag, omitClose); + Constructor.prototype.constructor = Constructor; + + var ConvenienceConstructor = function(props, children) { + var instance = new Constructor(); + instance.construct.apply(instance, arguments); + return instance; + }; + ConvenienceConstructor.componentConstructor = Constructor; + return ConvenienceConstructor; } /** - * Utility for constructing enums with keys being equal to the associated - * values, even when using advanced key crushing. This is useful for debugging, - * but also for using the values themselves as lookups into the enum. - * Example: - * var COLORS = keyMirror({blue: null, red: null}); - * var myColor = COLORS.blue; - * var isColorValid = !!COLORS[myColor] - * The last line could not be performed if the values of the generated enum were - * not equal to their keys. - * Input: {key1: val1, key2: val2} - * Output: {key1: key1, key2: key2} + * Creates a mapping from supported HTML tags to `ReactNativeComponent` classes. + * This is also accessible via `React.DOM`. + * + * @public */ -var keyMirror = function(obj) { - var ret = {}; - var key; +var ReactDOM = objMapKeyVal({ + a: false, + abbr: false, + address: false, + area: false, + article: false, + aside: false, + audio: false, + b: false, + base: false, + bdi: false, + bdo: false, + big: false, + blockquote: false, + body: false, + br: true, + button: false, + canvas: false, + caption: false, + cite: false, + code: false, + col: true, + colgroup: false, + data: false, + datalist: false, + dd: false, + del: false, + details: false, + dfn: false, + div: false, + dl: false, + dt: false, + em: false, + embed: true, + fieldset: false, + figcaption: false, + figure: false, + footer: false, + form: false, // NOTE: Injected, see `ReactDOMForm`. + h1: false, + h2: false, + h3: false, + h4: false, + h5: false, + h6: false, + head: false, + header: false, + hr: true, + html: false, + i: false, + iframe: false, + img: true, + input: true, + ins: false, + kbd: false, + keygen: true, + label: false, + legend: false, + li: false, + link: false, + main: false, + map: false, + mark: false, + menu: false, + menuitem: false, // NOTE: Close tag should be omitted, but causes problems. + meta: true, + meter: false, + nav: false, + noscript: false, + object: false, + ol: false, + optgroup: false, + option: false, + output: false, + p: false, + param: true, + pre: false, + progress: false, + q: false, + rp: false, + rt: false, + ruby: false, + s: false, + samp: false, + script: false, + section: false, + select: false, + small: false, + source: false, + span: false, + strong: false, + style: false, + sub: false, + summary: false, + sup: false, + table: false, + tbody: false, + td: false, + textarea: false, // NOTE: Injected, see `ReactDOMTextarea`. + tfoot: false, + th: false, + thead: false, + time: false, + title: false, + tr: false, + track: true, + u: false, + ul: false, + 'var': false, + video: false, + wbr: false, - throwIf(!(obj instanceof Object) || Array.isArray(obj), NOT_OBJECT_ERROR); + // SVG + circle: false, + g: false, + line: false, + path: false, + polyline: false, + rect: false, + svg: false, + text: false +}, createDOMComponentClass); - for (key in obj) { - if (!obj.hasOwnProperty(key)) { - continue; - } - ret[key] = key; +var injection = { + injectComponentClasses: function(componentClasses) { + mergeInto(ReactDOM, componentClasses); } - return ret; }; -module.exports = keyMirror; +ReactDOM.injection = injection; -},{"./throwIf":31}],12:[function(require,module,exports){ +module.exports = ReactDOM; + +},{"./ReactNativeComponent":40,"./mergeInto":83,"./objMapKeyVal":85}],26:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -2302,30 +4674,45 @@ module.exports = keyMirror; * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule merge + * @providesModule ReactDOMForm */ "use strict"; -var mergeInto = require("./mergeInto"); +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); +var ReactEventEmitter = require("./ReactEventEmitter"); +var EventConstants = require("./EventConstants"); + +// Store a reference to the `ReactNativeComponent`. +var form = ReactDOM.form; /** - * Shallow merges two structures into a return value, without mutating either. - * - * @param {?object} one Optional object with properties to merge from. - * @param {?object} two Optional object with properties to merge from. - * @return {object} The shallow extension of one by two. + * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need + * to capture it on the element itself. There are lots of hacks we could + * do to accomplish this, but the most reliable is to make a + * composite component and use `componentDidMount` to attach the event handlers. */ -var merge = function(one, two) { - var result = {}; - mergeInto(result, one); - mergeInto(result, two); - return result; -}; +var ReactDOMForm = ReactCompositeComponent.createClass({ + render: function() { + // TODO: Instead of using `ReactDOM` directly, we should use JSX. However, + // `jshint` fails to parse JSX so in order for linting to work in the open + // source repo, we need to just use `ReactDOM.form`. + return this.transferPropsTo(form(null, this.props.children)); + }, -module.exports = merge; + componentDidMount: function(node) { + ReactEventEmitter.trapBubbledEvent( + EventConstants.topLevelTypes.topSubmit, + 'submit', + node + ); + } +}); + +module.exports = ReactDOMForm; -},{"./mergeInto":18}],15:[function(require,module,exports){ +},{"./EventConstants":13,"./ReactCompositeComponent":23,"./ReactDOM":25,"./ReactEventEmitter":33}],27:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * @@ -2342,7 +4729,7 @@ module.exports = merge; * limitations under the License. * * @providesModule ReactDOMIDOperations - * @typechecks + * @typechecks static-only */ /*jslint evil: true */ @@ -2352,7 +4739,7 @@ module.exports = merge; var CSSPropertyOperations = require("./CSSPropertyOperations"); var DOMChildrenOperations = require("./DOMChildrenOperations"); var DOMPropertyOperations = require("./DOMPropertyOperations"); -var ReactDOMNodeCache = require("./ReactDOMNodeCache"); +var ReactID = require("./ReactID"); var getTextContentAccessor = require("./getTextContentAccessor"); var invariant = require("./invariant"); @@ -2364,7 +4751,6 @@ var invariant = require("./invariant"); * @private */ var INVALID_PROPERTY_ERRORS = { - content: '`content` must be set using `updateTextContentByID()`.', dangerouslySetInnerHTML: '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.', style: '`style` must be set using `updateStylesByID()`.' @@ -2394,7 +4780,7 @@ var ReactDOMIDOperations = { * @internal */ updatePropertyByID: function(id, name, value) { - var node = ReactDOMNodeCache.getCachedNodeByID(id); + var node = ReactID.getNode(id); invariant( !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), 'updatePropertyByID(...): %s', @@ -2403,6 +4789,24 @@ var ReactDOMIDOperations = { DOMPropertyOperations.setValueForProperty(node, name, value); }, + /** + * Updates a DOM node to remove a property. This should only be used to remove + * DOM properties in `DOMProperty`. + * + * @param {string} id ID of the node to update. + * @param {string} name A property name to remove, see `DOMProperty`. + * @internal + */ + deletePropertyByID: function(id, name, value) { + var node = ReactID.getNode(id); + invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[name] + ); + DOMPropertyOperations.deleteValueForProperty(node, name, value); + }, + /** * This should almost never be used instead of `updatePropertyByID()` due to * the extra object allocation required by the API. That said, this is useful @@ -2423,14 +4827,15 @@ var ReactDOMIDOperations = { }, /** - * Updates a DOM node with new style values. + * Updates a DOM node with new style values. If a value is specified as '', + * the corresponding style property will be unset. * * @param {string} id ID of the node to update. * @param {object} styles Mapping from styles to values. * @internal */ updateStylesByID: function(id, styles) { - var node = ReactDOMNodeCache.getCachedNodeByID(id); + var node = ReactID.getNode(id); CSSPropertyOperations.setValueForStyles(node, styles); }, @@ -2442,7 +4847,7 @@ var ReactDOMIDOperations = { * @internal */ updateInnerHTMLByID: function(id, html) { - var node = ReactDOMNodeCache.getCachedNodeByID(id); + var node = ReactID.getNode(id); // HACK: IE8- normalize whitespace in innerHTML, removing leading spaces. // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html node.innerHTML = (html && html.__html || '').replace(/^ /g, ' '); @@ -2456,7 +4861,7 @@ var ReactDOMIDOperations = { * @internal */ updateTextContentByID: function(id, content) { - var node = ReactDOMNodeCache.getCachedNodeByID(id); + var node = ReactID.getNode(id); node[textContentAccessor] = content; }, @@ -2469,32 +4874,142 @@ var ReactDOMIDOperations = { * @see {Danger.dangerouslyReplaceNodeWithMarkup} */ dangerouslyReplaceNodeWithMarkupByID: function(id, markup) { - var node = ReactDOMNodeCache.getCachedNodeByID(id); + var node = ReactID.getNode(id); DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); - ReactDOMNodeCache.purgeEntireCache(); }, - /** - * TODO: We only actually *need* to purge the cache when we remove elements. - * Detect if any elements were removed instead of blindly purging. - */ - manageChildrenByParentID: function(parentID, domOperations) { - var parent = ReactDOMNodeCache.getCachedNodeByID(parentID); - DOMChildrenOperations.manageChildren(parent, domOperations); - ReactDOMNodeCache.purgeEntireCache(); + /** + * TODO: We only actually *need* to purge the cache when we remove elements. + * Detect if any elements were removed instead of blindly purging. + */ + manageChildrenByParentID: function(parentID, domOperations) { + var parent = ReactID.getNode(parentID); + DOMChildrenOperations.manageChildren(parent, domOperations); + } + +}; + +module.exports = ReactDOMIDOperations; + +})() +},{"./CSSPropertyOperations":3,"./DOMChildrenOperations":6,"./DOMPropertyOperations":8,"./ReactID":35,"./getTextContentAccessor":71,"./invariant":75}],28:[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 ReactDOMInput + */ + +"use strict"; + +var DOMPropertyOperations = require("./DOMPropertyOperations"); +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); + +var merge = require("./merge"); + +// Store a reference to the `ReactNativeComponent`. +var input = ReactDOM.input; + +/** + * Implements an native component that allows setting these optional + * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. + * + * If `checked` or `value` are not supplied (or null/undefined), user actions + * that affect the checked state or value will trigger updates to the element. + * + * If they are supplied (and not null/undefined), the rendered element will not + * trigger updates to the element. Instead, the props must change in order for + * the rendered element to be updated. + * + * The rendered element will be initialized as unchecked (or `defaultChecked`) + * with an empty value (or `defaultValue`). + * + * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html + */ +var ReactDOMInput = ReactCompositeComponent.createClass({ + + getInitialState: function() { + return { + checked: this.props.defaultChecked || false, + value: this.props.defaultValue || '' + }; + }, + + shouldComponentUpdate: function() { + // Defer any updates to this component during the `onChange` handler. + return !this._isChanging; + }, + + getChecked: function() { + return this.props.checked != null ? this.props.checked : this.state.checked; + }, + + getValue: function() { + // Cast `this.props.value` to a string so equality checks pass. + return this.props.value != null ? '' + this.props.value : this.state.value; + }, + + render: function() { + // Clone `this.props` so we don't mutate the input. + var props = merge(this.props); + + props.checked = this.getChecked(); + props.value = this.getValue(); + props.onChange = this.handleChange; + + return input(props, this.props.children); + }, + + componentDidUpdate: function(prevProps, prevState, rootNode) { + if (this.props.checked != null) { + DOMPropertyOperations.setValueForProperty( + rootNode, + 'checked', + this.props.checked || false + ); + } + if (this.props.value != null) { + // Cast `this.props.value` to a string so falsey values that cast to + // truthy strings are not ignored. + DOMPropertyOperations.setValueForProperty( + rootNode, + 'value', + '' + this.props.value || '' + ); + } }, - setTextNodeValueAtIndexByParentID: function(parentID, index, value) { - var parent = ReactDOMNodeCache.getCachedNodeByID(parentID); - DOMChildrenOperations.setTextNodeValueAtIndex(parent, index, value); + handleChange: function(event) { + var returnValue; + if (this.props.onChange) { + this._isChanging = true; + returnValue = this.props.onChange(event); + this._isChanging = false; + } + this.setState({ + checked: event.target.checked, + value: event.target.value + }); + return returnValue; } -}; +}); -module.exports = ReactDOMIDOperations; +module.exports = ReactDOMInput; -})() -},{"./CSSPropertyOperations":32,"./DOMChildrenOperations":33,"./DOMPropertyOperations":34,"./ReactDOMNodeCache":35,"./getTextContentAccessor":36,"./invariant":10}],16:[function(require,module,exports){ +},{"./DOMPropertyOperations":8,"./ReactCompositeComponent":23,"./ReactDOM":25,"./merge":81}],29:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * @@ -2510,154 +5025,43 @@ module.exports = ReactDOMIDOperations; * See the License for the specific language governing permissions and * limitations under the License. * - * @providesModule ReactReconcileTransaction - * @typechecks + * @providesModule ReactDOMOption */ "use strict"; -var ExecutionEnvironment = require("./ExecutionEnvironment"); -var PooledClass = require("./PooledClass"); -var ReactEvent = require("./ReactEvent"); -var ReactInputSelection = require("./ReactInputSelection"); -var ReactOnDOMReady = require("./ReactOnDOMReady"); -var Transaction = require("./Transaction"); - -var mixInto = require("./mixInto"); - -/** - * Ensures that, when possible, the selection range (currently selected text - * input) is not disturbed by performing the transaction. - */ -var SELECTION_RESTORATION = { - /** - * @return {Selection} Selection information. - */ - initialize: ReactInputSelection.getSelectionInformation, - /** - * @param {Selection} sel Selection information returned from `initialize`. - */ - close: ReactInputSelection.restoreSelection -}; - -/** - * Suppresses events (blur/focus) that could be inadvertently dispatched due to - * high level DOM manipulations (like temporarily removing a text input from the - * DOM). - */ -var EVENT_SUPPRESSION = { - /** - * @return {boolean} The enabled status of `ReactEvent` before the - * reconciliation. - */ - initialize: function() { - var currentlyEnabled = ReactEvent.isEnabled(); - ReactEvent.setEnabled(false); - return currentlyEnabled; - }, - - /** - * @param {boolean} previouslyEnabled The enabled status of `ReactEvent` - * before the reconciliation occured. `close` restores the previous value. - */ - close: function(previouslyEnabled) { - ReactEvent.setEnabled(previouslyEnabled); - } -}; - -/** - * Provides a `ReactOnDOMReady` queue for collecting `onDOMReady` callbacks - * during the performing of the transaction. - */ -var ON_DOM_READY_QUEUEING = { - /** - * Initializes the internal `onDOMReady` queue. - */ - initialize: function() { - this.reactOnDOMReady.reset(); - }, - - /** - * After DOM is flushed, invoke all registered `onDOMReady` callbacks. - */ - close: function() { - this.reactOnDOMReady.notifyAll(); - } -}; +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); -/** - * Executed within the scope of the `Transaction` instance. Consider these as - * being member methods, but with an implied ordering while being isolated from - * each other. - */ -var TRANSACTION_WRAPPERS = [ - SELECTION_RESTORATION, - EVENT_SUPPRESSION, - ON_DOM_READY_QUEUEING -]; +// Store a reference to the