diff --git a/buildin/__webpack_console.js b/buildin/__webpack_console.js new file mode 100644 index 000000000..6d7de1678 --- /dev/null +++ b/buildin/__webpack_console.js @@ -0,0 +1,19 @@ +exports.log = (console && console.log) || function() {}; +exports.info = (console && console.info) || function() {}; +exports.error = (console && console.error) || function() {}; +exports.warn = (console && console.warn) || function() {}; +exports.dir = (console && console.dir) || function() {}; +exports.time = (console && console.time) || function(label) { + times[label] = Date.now(); +}; +exports.timeEnd = (console && console.timeEnd) || function() { + var duration = Date.now() - times[label]; + exports.log('%s: %dms', label, duration); +}; +exports.trace = (console && console.trace) || function() {}; +exports.assert = (console && console.assert) || function() { + if (!expression) { + var arr = Array.prototype.slice.call(arguments, 1); + require('assert').ok(false, util.format.apply(this, arr)); + } +}; \ No newline at end of file diff --git a/buildin/__webpack_module.js b/buildin/__webpack_module.js new file mode 100644 index 000000000..55edcc846 --- /dev/null +++ b/buildin/__webpack_module.js @@ -0,0 +1,2 @@ +exports.deprecate = function() {}; +exports.id = "webpack"; \ No newline at end of file diff --git a/buildin/__webpack_process.js b/buildin/__webpack_process.js new file mode 100644 index 000000000..842da7f3c --- /dev/null +++ b/buildin/__webpack_process.js @@ -0,0 +1,21 @@ +exports = module.exports = new (require("events").EventEmitter); +if(Object.prototype.__defineGetter__) { + exports.__defineGetter__("title", function() { return window.title; }); + exports.__defineSetter__("title", function(t) { window.title = t; }); +} else { + exports.title = window.title; +} +exports.version = exports.arch = +exports.platform = exports.execPath = "webpack"; +// TODO stdin, stdout, stderr +exports.argv = ["webpack", "browser"]; +exports.pid = 1; +exports.nextTick = function(func) { + setTimeout(func, 0); +} +exports.exit = exports.kill = +exports.chdir = exports.cwd = +exports.umask = exports.dlopen = +exports.uptime = exports.memoryUsage = +exports.uvCounters = exports.binding = function() {}; +exports.features = {}; \ No newline at end of file diff --git a/buildin/web_modules/assert.js b/buildin/web_modules/assert.js new file mode 100644 index 000000000..7e932be14 --- /dev/null +++ b/buildin/web_modules/assert.js @@ -0,0 +1,336 @@ +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// UTILITY +var util = require('util'); +var pSlice = Array.prototype.slice; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.message = options.message; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } +}; +util.inherits(assert.AssertionError, Error); + +function replacer(key, value) { + if (value === undefined) { + return '' + value; + } + if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) { + return value.toString(); + } + if (typeof value === 'function' || value instanceof RegExp) { + return value.toString(); + } + return value; +} + +function truncate(s, n) { + if (typeof s == 'string') { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} + +assert.AssertionError.prototype.toString = function() { + if (this.message) { + return [this.name + ':', this.message].join(' '); + } else { + return [ + this.name + ':', + truncate(JSON.stringify(this.actual, replacer), 128), + this.operator, + truncate(JSON.stringify(this.expected, replacer), 128) + ].join(' '); + } +}; + +// assert.AssertionError instanceof Error + +assert.AssertionError.__proto__ = Error.prototype; + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!!!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (actual instanceof RegExp && expected instanceof RegExp) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual == expected; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isUndefinedOrNull(value) { + return value === null || value === undefined; +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + try { + var ka = Object.keys(a), + kb = Object.keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (expected instanceof RegExp) { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail('Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail('Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function(err) { if (err) {throw err;}}; diff --git a/buildin/web_modules/child_process.js b/buildin/web_modules/child_process.js new file mode 100644 index 000000000..8467eda83 --- /dev/null +++ b/buildin/web_modules/child_process.js @@ -0,0 +1,5 @@ +exports.fork = exports.exec = +exports.execFile = exports.spawn = +function() { + throw new Error("child_process is not availibe in browser"); +} \ No newline at end of file diff --git a/buildin/web_modules/events.js b/buildin/web_modules/events.js new file mode 100644 index 000000000..1fff1e361 --- /dev/null +++ b/buildin/web_modules/events.js @@ -0,0 +1,218 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var isArray = Array.isArray; + +function EventEmitter() { } +exports.EventEmitter = EventEmitter; + +// By default EventEmitters will print a warning if more than +// 10 listeners are added to it. This is a useful default which +// helps finding memory leaks. +// +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +var defaultMaxListeners = 10; +EventEmitter.prototype.setMaxListeners = function(n) { + if (!this._events) this._events = {}; + this._maxListeners = n; +}; + + +EventEmitter.prototype.emit = function() { + var type = arguments[0]; + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events || !this._events.error || + (isArray(this._events.error) && !this._events.error.length)) + { + if (arguments[1] instanceof Error) { + throw arguments[1]; // Unhandled 'error' event + } else { + throw new Error("Uncaught, unspecified 'error' event."); + } + return false; + } + } + + if (!this._events) return false; + var handler = this._events[type]; + if (!handler) return false; + + if (typeof handler == 'function') { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + handler.apply(this, args); + } + return true; + + } else if (isArray(handler)) { + var l = arguments.length; + var args = new Array(l - 1); + for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; + + var listeners = handler.slice(); + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + return true; + + } else { + return false; + } +}; + +// EventEmitter is defined in src/node_events.cc +// EventEmitter.prototype.emit() is also defined there. +EventEmitter.prototype.addListener = function(type, listener) { + if ('function' !== typeof listener) { + throw new Error('addListener only takes instances of Function'); + } + + if (!this._events) this._events = {}; + + // To avoid recursion in the case that type == "newListeners"! Before + // adding it to the listeners, first emit "newListeners". + this.emit('newListener', type, typeof listener.listener === 'function' ? + listener.listener : listener); + + if (!this._events[type]) { + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + } else if (isArray(this._events[type])) { + + // If we've already got an array, just append. + this._events[type].push(listener); + + } else { + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + } + + // Check for listener leak + if (isArray(this._events[type]) && !this._events[type].warned) { + var m; + if (this._maxListeners !== undefined) { + m = this._maxListeners; + } else { + m = defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + console.trace(); + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if ('function' !== typeof listener) { + throw new Error('.once only takes instances of Function'); + } + + var self = this; + function g() { + self.removeListener(type, g); + listener.apply(this, arguments); + }; + + g.listener = listener; + self.on(type, g); + + return this; +}; + +EventEmitter.prototype.removeListener = function(type, listener) { + if ('function' !== typeof listener) { + throw new Error('removeListener only takes instances of Function'); + } + + // does not use listeners(), so no side effect of creating _events[type] + if (!this._events || !this._events[type]) return this; + + var list = this._events[type]; + + if (isArray(list)) { + var position = -1; + for (var i = 0, length = list.length; i < length; i++) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) + { + position = i; + break; + } + } + + if (position < 0) return this; + list.splice(position, 1); + if (list.length == 0) + delete this._events[type]; + } else if (list === listener || + (list.listener && list.listener === listener)) + { + delete this._events[type]; + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + if (arguments.length === 0) { + this._events = {}; + return this; + } + + // does not use listeners(), so no side effect of creating _events[type] + if (type && this._events && this._events[type]) this._events[type] = null; + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + if (!this._events) this._events = {}; + if (!this._events[type]) this._events[type] = []; + if (!isArray(this._events[type])) { + this._events[type] = [this._events[type]]; + } + return this._events[type]; +}; diff --git a/buildin/web_modules/util.js b/buildin/web_modules/util.js new file mode 100644 index 000000000..c7fcbccc8 --- /dev/null +++ b/buildin/web_modules/util.js @@ -0,0 +1,520 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (typeof f !== 'string') { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': return JSON.stringify(args[i++]); + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (x === null || typeof x !== 'object') { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +exports.print = function() { + for (var i = 0, len = arguments.length; i < len; ++i) { + process.stdout.write(String(arguments[i])); + } +}; + + +exports.puts = function() { + for (var i = 0, len = arguments.length; i < len; ++i) { + process.stdout.write(arguments[i] + '\n'); + } +}; + + +exports.debug = function(x) { + process.stderr.write('DEBUG: ' + x + '\n'); +}; + + +var error = exports.error = function(x) { + for (var i = 0, len = arguments.length; i < len; ++i) { + process.stderr.write(arguments[i] + '\n'); + } +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Boolean} showHidden Flag that shows hidden (not enumerable) + * properties of objects. + * @param {Number} depth Depth in which to descend in object. Default is 2. + * @param {Boolean} colors Flag to turn on ANSI escape codes to color the + * output. Default is false (no coloring). + */ +function inspect(obj, showHidden, depth, colors) { + var ctx = { + showHidden: showHidden, + seen: [], + stylize: colors ? stylizeWithColor : stylizeNoColor + }; + return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +var colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +var styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = styles[styleType]; + + if (style) { + return '\033[' + colors[style][0] + 'm' + str + + '\033[' + colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (value && typeof value.inspect === 'function' && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + return value.inspect(recurseTimes); + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var visibleKeys = Object.keys(value); + var keys = ctx.showHidden ? Object.getOwnPropertyNames(value) : visibleKeys; + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (typeof value === 'function') { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (typeof value === 'function') { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + switch (typeof value) { + case 'undefined': + return ctx.stylize('undefined', 'undefined'); + + case 'string': + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + + case 'number': + return ctx.stylize('' + value, 'number'); + + case 'boolean': + return ctx.stylize('' + value, 'boolean'); + } + // For some reason typeof null is "object", so special case here. + if (value === null) { + return ctx.stylize('null', 'null'); + } +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (Object.prototype.hasOwnProperty.call(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (visibleKeys.indexOf(key) < 0) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (recurseTimes === null) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (typeof name === 'undefined') { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar) || + (typeof ar === 'object' && objectToString(ar) === '[object Array]'); +} +exports.isArray = isArray; + + +function isRegExp(re) { + return typeof re === 'object' && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + + +function isDate(d) { + return typeof d === 'object' && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + + +function isError(e) { + return typeof e === 'object' && objectToString(e) === '[object Error]'; +} +exports.isError = isError; + + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +exports.p = function() { + for (var i = 0, len = arguments.length; i < len; ++i) { + error(exports.inspect(arguments[i])); + } +}; +module.deprecate('p', 'Use `util.puts(util.inspect())` instead.'); + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +exports.log = function(msg) { + exports.puts(timestamp() + ' - ' + msg.toString()); +}; + + +exports.exec = function() { + return require('child_process').exec.apply(this, arguments); +}; +module.deprecate('exec', 'It is now called `child_process.exec`.'); + + +exports.pump = function(readStream, writeStream, callback) { + var callbackCalled = false; + + function call(a, b, c) { + if (callback && !callbackCalled) { + callback(a, b, c); + callbackCalled = true; + } + } + + readStream.addListener('data', function(chunk) { + if (writeStream.write(chunk) === false) readStream.pause(); + }); + + writeStream.addListener('drain', function() { + readStream.resume(); + }); + + readStream.addListener('end', function() { + writeStream.end(); + }); + + readStream.addListener('close', function() { + call(); + }); + + readStream.addListener('error', function(err) { + writeStream.end(); + call(err); + }); + + writeStream.addListener('error', function(err) { + readStream.destroy(); + call(err); + }); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = function(ctor, superCtor) { + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); +}; + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; diff --git a/lib/buildDeps.js b/lib/buildDeps.js index fd46588ec..8c18ecc1b 100644 --- a/lib/buildDeps.js +++ b/lib/buildDeps.js @@ -84,7 +84,7 @@ function addModule(depTree, context, module, options, reason, callback) { } var deps; try { - deps = parse(source); + deps = parse(source, options.parse); } catch(e) { callback("File \"" + filename + "\" parsing failed: " + e); return; diff --git a/lib/parse.js b/lib/parse.js index 2da4a284c..75b061426 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -78,17 +78,15 @@ function walkStatement(context, statement) { // Declarations case "FunctionDeclaration": - var req = functionParamsContainsRequire(statement.params); - if(req) { - var old = context.requireOverwrite; - context.requireOverwrite = true; + if(statement.name in context.options.overwrites) { + context.overwrite.push(statement.name); } + var old = addOverwrites(context, statement.params); if(statement.body.type === "BlockStatement") walkStatement(context, statement.body); else walkExpression(context, statement.body); - if(req) - context.requireOverwrite = old; + context.overwrite.length = old; break; case "VariableDeclaration": if(statement.declarations) @@ -117,6 +115,9 @@ function walkVariableDeclarators(context, declarators) { declarators.forEach(function(declarator) { switch(declarator.type) { case "VariableDeclarator": + if(declarator.name in context.options.overwrites) { + context.overwrite.push(declarator.name); + } if(declarator.init) walkExpression(context, declarator.init); break; @@ -142,21 +143,12 @@ function walkExpression(context, expression) { }); break; case "FunctionExpression": - var req = functionParamsContainsRequire(expression.params); - if(context.paramMustRequire) { - req = false; - context.paramMustRequire = false; - } - if(req) { - var old = context.requireOverwrite; - context.requireOverwrite = true; - } + var old = addOverwrites(context, expression.params); if(expression.body.type === "BlockStatement") walkStatement(context, expression.body); else walkExpression(context, expression.body); - if(req) - context.requireOverwrite = old; + context.overwrite.length = old; break; case "SequenceExpression": if(expression.expressions) @@ -184,7 +176,7 @@ function walkExpression(context, expression) { break; case "CallExpression": var noCallee = false; - if(!context.requireOverwrite && + if(context.overwrite.indexOf("require") === -1 && expression.callee && expression.arguments && expression.arguments.length == 1 && expression.callee.type === "Identifier" && @@ -222,14 +214,14 @@ function walkExpression(context, expression) { context.requires = context.requires || []; context.requires.push({ name: param.value, - nameRange: param.range, + expressionRange: [expression.callee.range[0], expression.range[1]], line: expression.loc.start.line, column: expression.loc.start.column }); } noCallee = true; } - if(!context.requireOverwrite && + if(context.overwrite.indexOf("require") === -1 && expression.callee && expression.arguments && expression.arguments.length >= 1 && expression.callee.type === "MemberExpression" && @@ -244,7 +236,9 @@ function walkExpression(context, expression) { namesRange: expression.arguments[0].range, line: expression.loc.start.line, column: expression.loc.start.column, - paramMustRequire: true + ignoreOverride: true, + overwrite: context.overwrite.slice(), + options: context.options }; param.forEach(function(r) { newContext.requires.push({name: r}); @@ -253,7 +247,7 @@ function walkExpression(context, expression) { context = newContext; noCallee = true; } - if(!context.requireOverwrite && + if(context.overwrite.indexOf("require") === -1 && expression.callee && expression.arguments && expression.arguments.length == 1 && expression.callee.type === "MemberExpression" && @@ -267,7 +261,7 @@ function walkExpression(context, expression) { name: param, expressionRange: [expression.callee.range[0], expression.range[1]], line: expression.loc.start.line, - column: expression.loc.start.column, + column: expression.loc.start.column }; context.contexts.push(newContext); noCallee = true; @@ -279,12 +273,17 @@ function walkExpression(context, expression) { walkExpressions(context, expression.arguments); break; case "MemberExpression": + if(expression.object.type === "Identifier" && + expression.object.name === "module" && + expression.property.type === "Identifier" && + expression.property.name === "exports") + break; walkExpression(context, expression.object); if(expression.property.type !== "Identifier") walkExpression(context, expression.property); break; case "Identifier": - if(!context.requireOverwrite && + if(context.overwrite.indexOf("require") === -1 && expression.name === "require") { context.contexts = context.contexts || []; var newContext = { @@ -293,9 +292,18 @@ function walkExpression(context, expression) { require: true, calleeRange: [expression.range[0], expression.range[1]], line: expression.loc.start.line, - column: expression.loc.start.column, + column: expression.loc.start.column }; context.contexts.push(newContext); + } else if(context.overwrite.indexOf(expression.name) === -1 && + expression.name in context.options.overwrites) { + context.requires = context.requires || []; + context.requires.push({ + name: context.options.overwrites[expression.name], + expressionRange: expression.range, + line: expression.loc.start.line, + column: expression.loc.start.column + }); } break; } @@ -312,6 +320,21 @@ function functionParamsContainsRequire(params) { return found; } +function addOverwrites(context, params) { + var l = context.overwrite.length; + if(!params) return l; + params.forEach(function(param) { + if(context.ignoreOverride) { + context.ignoreOverride = false; + return; + } + if(param.type === "Identifier" && + param.name in context.options.overwrites) + context.overwrite.push(param.name); + }); + return l; +} + function parseString(expression) { switch(expression.type) { case "BinaryExpression": @@ -363,7 +386,13 @@ module.exports = function parse(source, options) { var ast = esprima.parse(source, {range: true, loc: true, raw: true}); if(!ast || typeof ast != "object") throw new Error("Source couldn't be parsed"); - var context = {}; + options = options || {}; + options.overwrites = options.overwrites || {}; + options.overwrites.require = true; + var context = { + options: options, + overwrite: [] + }; walkStatements(context, ast.body); return context; } \ No newline at end of file diff --git a/lib/resolve.js b/lib/resolve.js index a6d25edb0..6f6a239fd 100644 --- a/lib/resolve.js +++ b/lib/resolve.js @@ -33,10 +33,10 @@ module.exports = function resolve(context, identifier, options, callback) { } callback(null, absoluteFilename); } - var identArray = identifier.split("/"); + var identArray = split(identifier); var contextArray = split(context); - if(identArray[0] === "." || identArray[0] === ".." || identArray[0] === "") { - var pathname = join(contextArray, identArray); + if(identArray[0] === "." || identArray[0] === ".." || identArray[0] === "" || identArray[0].match(/^[A-Z]:$/i)) { + var pathname = identArray[0][0] === "." ? join(contextArray, identArray) : path.join.apply(path, identArray); loadAsFile(pathname, options, function(err, absoluteFilename) { if(err) { loadAsDirectory(pathname, options, finalResult); @@ -140,7 +140,7 @@ function loadNodeModules(context, identifier, options, callback) { loadAsDirectory(pathname, options, function(err, absoluteFilename) { if(err) { if(dirs.length === 0) { - callback(true); + callback("no module in any path of paths"); return; } tryDir(dirs.shift()); diff --git a/lib/webpack.js b/lib/webpack.js index 2c8ec961f..3a5d970f3 100644 --- a/lib/webpack.js +++ b/lib/webpack.js @@ -54,6 +54,14 @@ module.exports = function(context, moduleName, options, callback) { callback = options; options = {}; } + options.parse = options.parse || {}; + options.parse.overwrites = options.parse.overwrites || {}; + options.parse.overwrites.process = options.parse.overwrites.process || ("__webpack_process"); + options.parse.overwrites.module = options.parse.overwrites.module || ("__webpack_module"); + options.resolve = options.resolve || {}; + options.resolve.paths = options.resolve.paths || []; + options.resolve.paths.unshift(path.join(path.dirname(__dirname), "buildin")); + options.resolve.paths.unshift(path.join(path.dirname(__dirname), "buildin", "web_modules")); buildDeps(context, moduleName, options, function(err, depTree) { if(err) { callback(err); diff --git a/lib/writeSource.js b/lib/writeSource.js index 37cd47d0e..68d6f63d0 100644 --- a/lib/writeSource.js +++ b/lib/writeSource.js @@ -9,14 +9,14 @@ function stringify(str) { module.exports = function(module) { var replaces = []; // { from: 123, to: 125, value: "4" } function genReplaceRequire(requireItem) { - if(requireItem.nameRange && requireItem.id !== undefined) { + if(requireItem.expressionRange && requireItem.id !== undefined) { var prefix = ""; if(requireItem.name) prefix += "/* " + requireItem.name + " */"; replaces.push({ - from: requireItem.nameRange[0], - to: requireItem.nameRange[1], - value: prefix + requireItem.id + from: requireItem.expressionRange[0], + to: requireItem.expressionRange[1], + value: "require(" + prefix + requireItem.id + ")" }); } } diff --git a/package.json b/package.json index 827a1165c..09f3f427d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webpack", - "version": "0.2.2", + "version": "0.2.3", "author": "Tobias Koppers @sokra", "description": "Packs CommonJs Modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand.", "dependencies": { diff --git a/test/browsertest/lib/index.web.js b/test/browsertest/lib/index.web.js index 8ec65dc00..dd3907974 100644 --- a/test/browsertest/lib/index.web.js +++ b/test/browsertest/lib/index.web.js @@ -34,6 +34,15 @@ require.ensure([], function(require) { window.test(contextRequire("./singluar").value === 2, "Context works in chunk"); var singl = "singl"; window.test(require("." + "/" + singl + "uar").value === 2, "Context works in chunk, when splitted"); + window.test(typeof module.id === "string", "module.id should be a string"); + window.test(process.argv && process.argv.length > 1, "process.argv should be an array"); + process.nextTick(function() { + sum2++; + }); + process.on("xyz", function() { + sum2++; + }); + process.emit("xyz"); }); require.ensure([], function(require) { @@ -57,6 +66,8 @@ require.ensure([], function(require) { require("./duplicate2"); sum++; }); +var sum2 = 0; setTimeout(function() { window.test(sum === 2, "Multiple callbacks on code load finish"); + window.test(sum2 === 2, "process.nextTick and process.emit/on should be polyfilled"); }, 3000);