bin/r.js in requirejs-rails-0.5.5 vs bin/r.js in requirejs-rails-0.5.6

- old
+ new

@@ -1,7 +1,7 @@ /** - * @license r.js 1.0.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 1.0.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ /* @@ -18,11 +18,11 @@ var requirejs, require, define; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, - version = '1.0.5', + version = '1.0.7', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, //Used by jslib/rhino/args.js rhinoArgs = args, @@ -100,21 +100,21 @@ fileName = process.argv[3]; } } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 1.0.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 1.0.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ /*jslint strict: false, plusplus: false, sub: true */ /*global window, navigator, document, importScripts, jQuery, setTimeout, opera */ (function () { //Change this version number for each release. - var version = "1.0.5", + var version = "1.0.7", commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g, currDirRegExp = /^\.\//, jsSuffixRegExp = /\.js$/, ostring = Object.prototype.toString, @@ -1154,10 +1154,11 @@ if (expired && noLoads) { //If wait time expired, throw error of unloaded modules. err = makeError("timeout", "Load timeout for modules: " + noLoads); err.requireType = "timeout"; err.requireModules = noLoads; + err.contextName = context.contextName; return req.onError(err); } //If still loading but a plugin is waiting on a regular module cycle //break the cycle. @@ -2974,19 +2975,21 @@ * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ -/*jslint plusplus: false, strict: false */ -/*global define: false */ +/*jslint plusplus: true */ +/*global define */ define('lang', function () { + 'use strict'; + var lang = { backSlashRegExp: /\\/g, ostring: Object.prototype.toString, - isArray: Array.isArray ? Array.isArray : function (it) { + isArray: Array.isArray || function (it) { return lang.ostring.call(it) === "[object Array]"; }, isFunction: function(it) { return lang.ostring.call(it) === "[object Function]"; @@ -2994,23 +2997,40 @@ isRegExp: function(it) { return it && it instanceof RegExp; }, + _mixin: function(dest, source, override){ + var name; + for (name in source) { + if(source.hasOwnProperty(name) + && (override || !dest.hasOwnProperty(name))) { + dest[name] = source[name]; + } + } + + return dest; // Object + }, + /** - * Simple function to mix in properties from source into target, - * but only if target does not already have a property of the same name. + * mixin({}, obj1, obj2) is allowed. If the last argument is a boolean, + * then the source objects properties are force copied over to dest. */ - mixin: function (target, source, override) { - //Use an empty object to avoid other bad JS code that modifies - //Object.prototype. - var empty = {}, prop; - for (prop in source) { - if (override || !(prop in target)) { - target[prop] = source[prop]; - } + mixin: function(dest){ + var parameters = Array.prototype.slice.call(arguments), + override, i, l; + + if (!dest) { dest = {}; } + + if (parameters.length > 2 && typeof arguments[parameters.length-1] === 'boolean') { + override = parameters.pop(); } + + for (i = 1, l = parameters.length; i < l; i++) { + lang._mixin(dest, parameters[i], override); + } + return dest; // Object }, delegate: (function () { // boodman/crockford delegation w/ cornford optimization function TMP() {} @@ -6575,11 +6595,11 @@ */ /*jslint plusplus: false, strict: false */ /*global define: false */ -define('parse', ['uglifyjs/index'], function (uglify) { +define('parse', ['./uglifyjs/index'], function (uglify) { var parser = uglify.parser, processor = uglify.uglify, ostring = Object.prototype.toString, isArray; @@ -7000,11 +7020,11 @@ * @param {String} fileContents * * @returns {Array} an array of dependency strings. The dependencies * have not been normalized, they may be relative IDs. */ - parse.findDependencies = function (fileName, fileContents) { + parse.findDependencies = function (fileName, fileContents, options) { //This is a litle bit inefficient, it ends up with two uglifyjs parser //calls. Can revisit later, but trying to build out larger functional //pieces first. var dependencies = [], astRoot = parser.parse(fileContents); @@ -7017,15 +7037,138 @@ } if ((deps = getValidDeps(deps))) { dependencies = dependencies.concat(deps); } + }, options); + + return dependencies; + }; + + /** + * Finds only CJS dependencies, ones that are the form require('stringLiteral') + */ + parse.findCjsDependencies = function (fileName, fileContents, options) { + //This is a litle bit inefficient, it ends up with two uglifyjs parser + //calls. Can revisit later, but trying to build out larger functional + //pieces first. + var dependencies = [], + astRoot = parser.parse(fileContents); + + parse.recurse(astRoot, function (dep) { + dependencies.push(dep); + }, options, function (node, onMatch) { + + var call, args; + + if (!isArray(node)) { + return false; + } + + if (node[0] === 'call') { + call = node[1]; + args = node[2]; + + if (call) { + //A require('') use. + if (call[0] === 'name' && call[1] === 'require' && + args[0][0] === 'string') { + return onMatch(args[0][1]); + } + } + } + + return false; + }); return dependencies; }; + /** + * Determines if define(), require({}|[]) or requirejs was called in the + * file. Also finds out if define() is declared and if define.amd is called. + */ + parse.usesAmdOrRequireJs = function (fileName, fileContents, options) { + var astRoot = parser.parse(fileContents), + uses; + + parse.recurse(astRoot, function (prop) { + if (!uses) { + uses = {}; + } + uses[prop] = true; + }, options, parse.findAmdOrRequireJsNode); + + return uses; + }; + + /** + * Determines if require(''), exports.x =, module.exports =, + * __dirname, __filename are used. So, not strictly traditional CommonJS, + * also checks for Node variants. + */ + parse.usesCommonJs = function (fileName, fileContents, options) { + var uses = null, + assignsExports = false, + astRoot = parser.parse(fileContents); + + parse.recurse(astRoot, function (prop) { + if (prop === 'varExports') { + assignsExports = true; + } else if (prop !== 'exports' || !assignsExports) { + if (!uses) { + uses = {}; + } + uses[prop] = true; + } + }, options, function (node, onMatch) { + + var call, args; + + if (!isArray(node)) { + return false; + } + + if (node[0] === 'name' && (node[1] === '__dirname' || node[1] === '__filename')) { + return onMatch(node[1].substring(2)); + } else if (node[0] === 'var' && node[1] && node[1][0] && node[1][0][0] === 'exports') { + //Hmm, a variable assignment for exports, so does not use cjs exports. + return onMatch('varExports'); + } else if (node[0] === 'assign' && node[2] && node[2][0] === 'dot') { + args = node[2][1]; + + if (args) { + //An exports or module.exports assignment. + if (args[0] === 'name' && args[1] === 'module' && + node[2][2] === 'exports') { + return onMatch('moduleExports'); + } else if (args[0] === 'name' && args[1] === 'exports') { + return onMatch('exports'); + } + } + } else if (node[0] === 'call') { + call = node[1]; + args = node[2]; + + if (call) { + //A require('') use. + if (call[0] === 'name' && call[1] === 'require' && + args[0][0] === 'string') { + return onMatch('require'); + } + } + } + + return false; + + }); + + return uses; + }; + + parse.findRequireDepNames = function (node, deps) { var moduleName, i, n, call, args; if (isArray(node)) { if (node[0] === 'call') { @@ -7179,11 +7322,59 @@ } return false; }; + /** + * Looks for define(), require({} || []), requirejs({} || []) calls. + */ + parse.findAmdOrRequireJsNode = function (node, onMatch) { + var call, args, configNode, type; + if (!isArray(node)) { + return false; + } + + if (node[0] === 'defun' && node[1] === 'define') { + type = 'declaresDefine'; + } else if (node[0] === 'assign' && node[2] && node[2][2] === 'amd' && + node[2][1] && node[2][1][0] === 'name' && + node[2][1][1] === 'define') { + type = 'defineAmd'; + } else if (node[0] === 'call') { + call = node[1]; + args = node[2]; + + if (call) { + if ((call[0] === 'dot' && + (call[1] && call[1][0] === 'name' && + (call[1][1] === 'require' || call[1][1] === 'requirejs')) && + call[2] === 'config')) { + //A require.config() or requirejs.config() call. + type = call[1][1] + 'Config'; + } else if (call[0] === 'name' && + (call[1] === 'require' || call[1] === 'requirejs')) { + //A require() or requirejs() config call. + //Only want ones that start with an object or an array. + configNode = args[0]; + if (configNode[0] === 'object' || configNode[0] === 'array') { + type = call[1]; + } + } else if (call[0] === 'name' && call[1] === 'define') { + //A define call. + type = 'define'; + } + } + } + + if (type) { + return onMatch(type); + } + + return false; + }; + /** * Determines if a specific node is a valid require/requirejs config * call. That includes calls to require/requirejs.config(). * @param {Array} node * @param {Function} onMatch a function to call when a match is found. @@ -7614,11 +7805,11 @@ * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ -/*jslint plusplus: false, nomen: false, regexp: false, strict: false */ +/*jslint plusplus: false, nomen: false, regexp: false */ /*global define: false */ define('optimize', [ 'lang', 'logger', 'env!env/optimize', 'env!env/file', 'parse', 'pragma', 'uglifyjs/index'], function (lang, logger, envOptimize, file, parse, @@ -7698,10 +7889,13 @@ //Make a file path based on the last slash. //If no slash, so must be just a file name. Use empty string then. importPath = (importEndIndex !== -1) ? importFileName.substring(0, importEndIndex + 1) : ""; + //fix url() on relative import (#5) + importPath = importPath.replace(/^\.\//, ''); + //Modify URL paths to match the path represented by this file. importContents = importContents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { fixedUrlMatch = cleanCssUrlQuotes(urlMatch); fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); @@ -7758,15 +7952,41 @@ */ jsFile: function (fileName, outFileName, config, moduleName, pluginCollector) { var parts = (config.optimize + "").split('.'), optimizerName = parts[0], keepLines = parts[1] === 'keepLines', - licenseContents = '', - fileContents, optFunc, match, comment; + fileContents; fileContents = file.readFile(fileName); + fileContents = optimize.js(fileName, fileContents, optimizerName, + keepLines, config, pluginCollector); + + file.saveUtf8File(outFileName, fileContents); + }, + + /** + * Optimizes a file that contains JavaScript content. Optionally collects + * plugin resources mentioned in a file, and then passes the content + * through an minifier if one is specified via config.optimize. + * + * @param {String} fileName the name of the file that matches the + * fileContents. + * @param {String} fileContents the string of JS to optimize. + * @param {String} [optimizerName] optional name of the optimizer to + * use. 'uglify' is default. + * @param {Boolean} [keepLines] whether to keep line returns in the optimization. + * @param {Object} [config] the build config object. + * @param {Array} [pluginCollector] storage for any plugin resources + * found. + */ + js: function (fileName, fileContents, optimizerName, keepLines, config, pluginCollector) { + var licenseContents = '', + optFunc, match, comment; + + config = config || {}; + //Apply pragmas/namespace renaming fileContents = pragma.process(fileName, fileContents, config, 'OnSave', pluginCollector); //Optimize the JS files if asked. if (optimizerName && optimizerName !== 'none') { @@ -7792,11 +8012,11 @@ fileContents = licenseContents + optFunc(fileName, fileContents, keepLines, config[optimizerName]); } - file.saveUtf8File(outFileName, fileContents); + return fileContents; }, /** * Optimizes one CSS file, inlining @import calls, stripping comments, and * optionally removes line returns. @@ -7885,11 +8105,12 @@ } } }; return optimize; -});/** +}); +/** * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ /* @@ -7976,17 +8197,17 @@ * optimization tool. * @param {String} url * @returns {Boolean} */ require._isSupportedBuildUrl = function (url) { - //Ignore URLs with protocols or question marks, means either network + //Ignore URLs with protocols, hosts or question marks, means either network //access is needed to fetch it or it is too dynamic. Note that //on Windows, full paths are used for some urls, which include //the drive, like c:/something, so need to test for something other //than just a colon. return url.indexOf("://") === -1 && url.indexOf("?") === -1 && - url.indexOf('empty:') !== 0; + url.indexOf('empty:') !== 0 && url.indexOf('//') !== 0; }; //Override define() to catch modules that just define an object, so that //a dummy define call is not put in the build file for them. They do //not end up getting defined via require.execCb, so we need to catch them @@ -8021,19 +8242,19 @@ //Override load so that the file paths can be collected. require.load = function (context, moduleName, url) { /*jslint evil: true */ var contents, pluginBuilderMatch, builderName; - //Adjust the URL if it was not transformed to use baseUrl. - url = normalizeUrlWithBase(context, moduleName, url); - context.scriptCount += 1; //Only handle urls that can be inlined, so that means avoiding some //URLs like ones that require network access or may be too dynamic, //like JSONP if (require._isSupportedBuildUrl(url)) { + //Adjust the URL if it was not transformed to use baseUrl. + url = normalizeUrlWithBase(context, moduleName, url); + //Save the module name to path and path to module name mappings. layer.buildPathMap[moduleName] = url; layer.buildFileToModule[url] = moduleName; if (moduleName in context.plugins) { @@ -8047,10 +8268,16 @@ contents = require._cachedFileContents[url]; } else { //Load the file contents, process for conditionals, then //evaluate it. contents = file.readFile(url); + + //If there is a read filter, run it now. + if (context.config.onBuildRead) { + contents = context.config.onBuildRead(moduleName, url, contents); + } + contents = pragma.process(url, contents, context.config, 'OnExecute'); //Find out if the file contains a require() definition. Need to know //this so we can inject plugins right after it, but before they are needed, //and to make sure this file is first, so that define calls work. @@ -8339,18 +8566,20 @@ * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ -/*jslint regexp: false, plusplus: false, nomen: false, strict: false */ -/*global define: false, require: false */ +/*jslint plusplus: true, nomen: true */ +/*global define, require */ define('build', [ 'lang', 'logger', 'env!env/file', 'parse', 'optimize', 'pragma', 'env!env/load', 'requirePatch'], function (lang, logger, file, parse, optimize, pragma, load, requirePatch) { + 'use strict'; + var build, buildBaseConfig, endsWithSemiColonRegExp = /;\s*$/; buildBaseConfig = { appDir: "", @@ -8386,11 +8615,11 @@ * people from using URLs with protocols in the build config, since * the optimizer is not set up to do network access. However, be * sure to allow absolute paths on Windows, like C:\directory. */ function disallowUrls(path) { - if (path.indexOf('://') !== -1 && path !== 'empty:') { + if ((path.indexOf('://') !== -1 || path.indexOf('//') === 0) && path !== 'empty:') { throw new Error('Path is not supported: ' + path + '\nOptimizer can only handle' + ' local paths. Download the locally if necessary' + ' and update the config to use a local path.\n' + 'http://requirejs.org/docs/errors.html#pathnotsupported'); @@ -8496,12 +8725,17 @@ file.copyDir((config.appDir || config.baseUrl), config.dir, /\w/, true); //Adjust baseUrl if config.appDir is in play, and set up build output paths. buildPaths = {}; if (config.appDir) { - //All the paths should be inside the appDir - buildPaths = paths; + //All the paths should be inside the appDir, so just adjust + //the paths to use the dirBaseUrl + for (prop in paths) { + if (paths.hasOwnProperty(prop)) { + buildPaths[prop] = paths[prop].replace(config.baseUrl, config.dirBaseUrl); + } + } } else { //If no appDir, then make sure to copy the other paths to this directory. for (prop in paths) { if (paths.hasOwnProperty(prop)) { //Set up build path for each path prefix. @@ -8867,36 +9101,29 @@ /** * For any path in a possible config, make it absolute relative * to the absFilePath passed in. */ build.makeAbsConfig = function (config, absFilePath) { - var props, prop, i, originalBaseUrl; + var props, prop, i; props = ["appDir", "dir", "baseUrl"]; for (i = 0; (prop = props[i]); i++) { if (config[prop]) { //Add abspath if necessary, make sure these paths end in //slashes if (prop === "baseUrl") { - originalBaseUrl = config.baseUrl; + config.originalBaseUrl = config.baseUrl; if (config.appDir) { //If baseUrl with an appDir, the baseUrl is relative to //the appDir, *not* the absFilePath. appDir and dir are //made absolute before baseUrl, so this will work. - config.baseUrl = build.makeAbsPath(originalBaseUrl, config.appDir); - //Set up dir output baseUrl. - config.dirBaseUrl = build.makeAbsPath(originalBaseUrl, config.dir); + config.baseUrl = build.makeAbsPath(config.originalBaseUrl, config.appDir); } else { //The dir output baseUrl is same as regular baseUrl, both //relative to the absFilePath. config.baseUrl = build.makeAbsPath(config[prop], absFilePath); - config.dirBaseUrl = config.dir || config.baseUrl; } - - //Make sure dirBaseUrl ends in a slash, since it is - //concatenated with other strings. - config.dirBaseUrl = endsWithSlash(config.dirBaseUrl); } else { config[prop] = build.makeAbsPath(config[prop], absFilePath); } config[prop] = endsWithSlash(config[prop]); @@ -8938,16 +9165,13 @@ //allow a one-level-deep mixing of it. value = source[prop]; if (typeof value === 'object' && value && !lang.isArray(value) && !lang.isFunction(value) && !lang.isRegExp(value)) { - if (!target[prop]) { - target[prop] = {}; - } - lang.mixin(target[prop], source[prop], true); + target[prop] = lang.mixin({}, target[prop], value, true); } else { - target[prop] = source[prop]; + target[prop] = value; } } } } @@ -8965,17 +9189,18 @@ build.createConfig = function (cfg) { /*jslint evil: true */ var config = {}, buildFileContents, buildFileConfig, mainConfig, mainConfigFile, prop, buildFile, absFilePath; - lang.mixin(config, buildBaseConfig); - lang.mixin(config, cfg, true); - //Make sure all paths are relative to current directory. absFilePath = file.absPath('.'); - build.makeAbsConfig(config, absFilePath); + build.makeAbsConfig(cfg, absFilePath); + build.makeAbsConfig(buildBaseConfig, absFilePath); + lang.mixin(config, buildBaseConfig); + lang.mixin(config, cfg, true); + if (config.buildFile) { //A build file exists, load it to get more config. buildFile = file.absPath(config.buildFile); //Find the build file, and make sure it exists, if this is a build @@ -9032,41 +9257,67 @@ //Re-apply the override config values. Command line //args should take precedence over build file values. mixConfig(config, cfg); + + //Set final output dir + if (config.hasOwnProperty("baseUrl")) { + if (config.appDir) { + config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir); + } else { + config.dirBaseUrl = config.dir || config.baseUrl; + } + //Make sure dirBaseUrl ends in a slash, since it is + //concatenated with other strings. + config.dirBaseUrl = endsWithSlash(config.dirBaseUrl); + } + //Check for errors in config if (config.cssIn && !config.out) { throw new Error("ERROR: 'out' option missing."); } if (!config.cssIn && !config.baseUrl) { throw new Error("ERROR: 'baseUrl' option missing."); } if (!config.out && !config.dir) { - throw new Error('Missing either an "out" or "dir" config value.'); + throw new Error('Missing either an "out" or "dir" config value. ' + + 'If using "appDir" for a full project optimization, ' + + 'use "dir". If you want to optimize to one file, ' + + 'use "out".'); } + if (config.appDir && config.out) { + throw new Error('"appDir" is not compatible with "out". Use "dir" ' + + 'instead. appDir is used to copy whole projects, ' + + 'where "out" is used to just optimize to one file.'); + } if (config.out && config.dir) { throw new Error('The "out" and "dir" options are incompatible.' + ' Use "out" if you are targeting a single file for' + ' for optimization, and "dir" if you want the appDir' + ' or baseUrl directories optimized.'); } - if (config.out && !config.cssIn) { - //Just one file to optimize. - - //Set up dummy module layer to build. + if ((config.name || config.include) && !config.modules) { + //Just need to build one file, but may be part of a whole appDir/ + //baseUrl copy, but specified on the command line, so cannot do + //the modules array setup. So create a modules section in that + //case. config.modules = [ { name: config.name, out: config.out, include: config.include, exclude: config.exclude, excludeShallow: config.excludeShallow } ]; + } + if (config.out && !config.cssIn) { + //Just one file to optimize. + //Does not have a build file, so set up some defaults. //Optimizing CSS should not be allowed, unless explicitly //asked for on command line. In that case the only task is //to optimize a CSS file. if (!cfg.optimizeCss) { @@ -9279,27 +9530,41 @@ builder = parts.prefix && context.defined[parts.prefix]; if (builder) { if (builder.write) { writeApi = function (input) { fileContents += "\n" + addSemiColon(input); + if (config.onBuildWrite) { + fileContents = config.onBuildWrite(moduleName, path, fileContents); + } }; writeApi.asModule = function (moduleName, input) { fileContents += "\n" + addSemiColon( build.toTransport(anonDefRegExp, namespace, moduleName, path, input, layer)); + if (config.onBuildWrite) { + fileContents = config.onBuildWrite(moduleName, path, fileContents); + } }; builder.write(parts.prefix, parts.name, writeApi); } } else { currContents = file.readFile(path); + if (config.onBuildRead) { + currContents = config.onBuildRead(moduleName, path, currContents); + } + if (config.namespace) { currContents = pragma.namespace(currContents, config.namespace); } currContents = build.toTransport(anonDefRegExp, namespace, moduleName, path, currContents, layer); + if (config.onBuildWrite) { + currContents = config.onBuildWrite(moduleName, path, currContents); + } + //Semicolon is for files that are not well formed when //concatenated with other content. fileContents += "\n" + addSemiColon(currContents); } @@ -9343,10 +9608,10 @@ //This regexp is not bullet-proof, and it has one optional part to //avoid issues with some Dojo transition modules that use a //define(\n//begin v1.x content //for a comment. return new RegExp('(^|[^\\.])(' + (namespace || '').replace(/\./g, '\\.') + - 'define|define)\\s*\\(\\s*(\\/\\/[^\\n\\r]*[\\r\\n])?(\\[|function|[\\w\\d_\\$]+\\s*\\)|\\{|["\']([^"\']+)["\'])(\\s*,\\s*f)?'); + 'define|define)\\s*\\(\\s*(\\/\\/[^\\n\\r]*[\\r\\n])?(\\[|function|[\\w\\d_\\-\\$]+\\s*\\)|\\{|["\']([^"\']+)["\'])(\\s*,\\s*f)?'); }; build.leadingCommaRegExp = /^\s*,/; build.toTransport = function (anonDefRegExp, namespace, moduleName, path, contents, layer) {